From d78ba8a8ccb17638f172d8d1a0c26c02c2cb6cbe Mon Sep 17 00:00:00 2001 From: Yonatan Komornik Date: Fri, 21 Jan 2022 14:07:53 -0800 Subject: [PATCH 01/23] Refactored fileio.c: - Extracted asyncio code to fileio_asyncio.c/.h - Moved type definitions to fileio_types.h - Moved common macro definitions needed by both fileio.c and fileio_asyncio.c to fileio_common.h --- build/VS2008/zstd/zstd.vcproj | 4 + build/VS2010/zstd/zstd.vcxproj | 1 + build/cmake/programs/CMakeLists.txt | 4 +- build/meson/programs/meson.build | 2 + contrib/VS2005/zstd/zstd.vcproj | 4 + programs/Makefile | 8 +- programs/fileio.c | 524 +++------------------------- programs/fileio.h | 8 +- programs/fileio_asycio.c | 355 +++++++++++++++++++ programs/fileio_asycio.h | 110 ++++++ programs/fileio_common.h | 107 ++++++ programs/fileio_types.h | 63 ++++ 12 files changed, 694 insertions(+), 496 deletions(-) create mode 100644 programs/fileio_asycio.c create mode 100644 programs/fileio_asycio.h create mode 100644 programs/fileio_common.h create mode 100644 programs/fileio_types.h diff --git a/build/VS2008/zstd/zstd.vcproj b/build/VS2008/zstd/zstd.vcproj index c7eec577db3..91f2bda536c 100644 --- a/build/VS2008/zstd/zstd.vcproj +++ b/build/VS2008/zstd/zstd.vcproj @@ -384,6 +384,10 @@ RelativePath="..\..\..\programs\fileio.c" > + + diff --git a/build/VS2010/zstd/zstd.vcxproj b/build/VS2010/zstd/zstd.vcxproj index 46e22f42e9b..8ab239dd814 100644 --- a/build/VS2010/zstd/zstd.vcxproj +++ b/build/VS2010/zstd/zstd.vcxproj @@ -62,6 +62,7 @@ + diff --git a/build/cmake/programs/CMakeLists.txt b/build/cmake/programs/CMakeLists.txt index 490030783d3..28b1e1d166b 100644 --- a/build/cmake/programs/CMakeLists.txt +++ b/build/cmake/programs/CMakeLists.txt @@ -32,7 +32,7 @@ if (MSVC) set(PlatformDependResources ${MSVC_RESOURCE_DIR}/zstd.rc) endif () -add_executable(zstd ${PROGRAMS_DIR}/zstdcli.c ${PROGRAMS_DIR}/util.c ${PROGRAMS_DIR}/timefn.c ${PROGRAMS_DIR}/fileio.c ${PROGRAMS_DIR}/benchfn.c ${PROGRAMS_DIR}/benchzstd.c ${PROGRAMS_DIR}/datagen.c ${PROGRAMS_DIR}/dibio.c ${PROGRAMS_DIR}/zstdcli_trace.c ${PlatformDependResources}) +add_executable(zstd ${PROGRAMS_DIR}/zstdcli.c ${PROGRAMS_DIR}/util.c ${PROGRAMS_DIR}/timefn.c ${PROGRAMS_DIR}/fileio.c ${PROGRAMS_DIR}/fileio_asyncio.c ${PROGRAMS_DIR}/benchfn.c ${PROGRAMS_DIR}/benchzstd.c ${PROGRAMS_DIR}/datagen.c ${PROGRAMS_DIR}/dibio.c ${PROGRAMS_DIR}/zstdcli_trace.c ${PlatformDependResources}) target_link_libraries(zstd ${PROGRAMS_ZSTD_LINK_TARGET}) if (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)") target_link_libraries(zstd rt) @@ -75,7 +75,7 @@ if (UNIX) ${CMAKE_CURRENT_BINARY_DIR}/zstdless.1 DESTINATION "${MAN_INSTALL_DIR}") - add_executable(zstd-frugal ${PROGRAMS_DIR}/zstdcli.c ${PROGRAMS_DIR}/util.c ${PROGRAMS_DIR}/timefn.c ${PROGRAMS_DIR}/fileio.c) + add_executable(zstd-frugal ${PROGRAMS_DIR}/zstdcli.c ${PROGRAMS_DIR}/util.c ${PROGRAMS_DIR}/timefn.c ${PROGRAMS_DIR}/fileio.c ${PROGRAMS_DIR}/fileio_asyncio.c) target_link_libraries(zstd-frugal ${PROGRAMS_ZSTD_LINK_TARGET}) set_property(TARGET zstd-frugal APPEND PROPERTY COMPILE_DEFINITIONS "ZSTD_NOBENCH;ZSTD_NODICT;ZSTD_NOTRACE") endif () diff --git a/build/meson/programs/meson.build b/build/meson/programs/meson.build index 0ae93fc107c..5ccd679a167 100644 --- a/build/meson/programs/meson.build +++ b/build/meson/programs/meson.build @@ -14,6 +14,7 @@ zstd_programs_sources = [join_paths(zstd_rootdir, 'programs/zstdcli.c'), join_paths(zstd_rootdir, 'programs/util.c'), join_paths(zstd_rootdir, 'programs/timefn.c'), join_paths(zstd_rootdir, 'programs/fileio.c'), + join_paths(zstd_rootdir, 'programs/fileio_asyncio.c'), join_paths(zstd_rootdir, 'programs/benchfn.c'), join_paths(zstd_rootdir, 'programs/benchzstd.c'), join_paths(zstd_rootdir, 'programs/datagen.c'), @@ -80,6 +81,7 @@ zstd_frugal_sources = [join_paths(zstd_rootdir, 'programs/zstdcli.c'), join_paths(zstd_rootdir, 'programs/timefn.c'), join_paths(zstd_rootdir, 'programs/util.c'), join_paths(zstd_rootdir, 'programs/fileio.c'), + join_paths(zstd_rootdir, 'programs/fileio_asyncio.c'), join_paths(zstd_rootdir, 'lib/common/pool.c'), join_paths(zstd_rootdir, 'lib/common/zstd_common.c'), join_paths(zstd_rootdir, 'lib/common/error_private.c')] diff --git a/contrib/VS2005/zstd/zstd.vcproj b/contrib/VS2005/zstd/zstd.vcproj index 78645d18a36..e37ebee3911 100644 --- a/contrib/VS2005/zstd/zstd.vcproj +++ b/contrib/VS2005/zstd/zstd.vcproj @@ -363,6 +363,10 @@ RelativePath="..\..\..\programs\fileio.c" > + + diff --git a/programs/Makefile b/programs/Makefile index f77e1b7f10f..82aa498950f 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -243,17 +243,17 @@ zstd-pgo : ## zstd-small: minimal target, supporting only zstd compression and decompression. no bench. no legacy. no other format. zstd-small: CFLAGS = -Os -s -zstd-frugal zstd-small: $(ZSTDLIB_CORE_SRC) zstdcli.c util.c timefn.c fileio.c +zstd-frugal zstd-small: $(ZSTDLIB_CORE_SRC) zstdcli.c util.c timefn.c fileio.c fileio_asycio.c $(CC) $(FLAGS) -DZSTD_NOBENCH -DZSTD_NODICT -DZSTD_NOTRACE -UZSTD_LEGACY_SUPPORT -DZSTD_LEGACY_SUPPORT=0 $^ -o $@$(EXT) -zstd-decompress: $(ZSTDLIB_COMMON_SRC) $(ZSTDLIB_DECOMPRESS_SRC) zstdcli.c util.c timefn.c fileio.c +zstd-decompress: $(ZSTDLIB_COMMON_SRC) $(ZSTDLIB_DECOMPRESS_SRC) zstdcli.c util.c timefn.c fileio.c fileio_asycio.c $(CC) $(FLAGS) -DZSTD_NOBENCH -DZSTD_NODICT -DZSTD_NOCOMPRESS -DZSTD_NOTRACE -UZSTD_LEGACY_SUPPORT -DZSTD_LEGACY_SUPPORT=0 $^ -o $@$(EXT) -zstd-compress: $(ZSTDLIB_COMMON_SRC) $(ZSTDLIB_COMPRESS_SRC) zstdcli.c util.c timefn.c fileio.c +zstd-compress: $(ZSTDLIB_COMMON_SRC) $(ZSTDLIB_COMPRESS_SRC) zstdcli.c util.c timefn.c fileio.c fileio_asycio.c $(CC) $(FLAGS) -DZSTD_NOBENCH -DZSTD_NODICT -DZSTD_NODECOMPRESS -DZSTD_NOTRACE -UZSTD_LEGACY_SUPPORT -DZSTD_LEGACY_SUPPORT=0 $^ -o $@$(EXT) ## zstd-dictBuilder: executable supporting dictionary creation and compression (only) -zstd-dictBuilder: $(ZSTDLIB_COMMON_SRC) $(ZSTDLIB_COMPRESS_SRC) $(ZDICT_SRC) zstdcli.c util.c timefn.c fileio.c dibio.c +zstd-dictBuilder: $(ZSTDLIB_COMMON_SRC) $(ZSTDLIB_COMPRESS_SRC) $(ZDICT_SRC) zstdcli.c util.c timefn.c fileio.c fileio_asycio.c dibio.c $(CC) $(FLAGS) -DZSTD_NOBENCH -DZSTD_NODECOMPRESS -DZSTD_NOTRACE $^ -o $@$(EXT) zstdmt: zstd diff --git a/programs/fileio.c b/programs/fileio.c index f5e2e488ca4..383c3dd107f 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -34,16 +34,18 @@ #include /* INT_MAX */ #include #include "timefn.h" /* UTIL_getTime, UTIL_clockSpanMicro */ -#include "../lib/common/pool.h" -#include "../lib/common/threading.h" #if defined (_MSC_VER) # include # include #endif -#include "../lib/common/mem.h" /* U32, U64 */ #include "fileio.h" +#include "fileio_asycio.h" +#include "fileio_common.h" + +FIO_display_prefs_t g_display_prefs = {2, FIO_ps_auto}; +UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER; #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_magicNumber, ZSTD_frameHeaderSize_max */ #include "../lib/zstd.h" @@ -84,62 +86,6 @@ #define DEFAULT_FILE_PERMISSIONS (0666) #endif -/*-************************************* -* Macros -***************************************/ -#define KB *(1 <<10) -#define MB *(1 <<20) -#define GB *(1U<<30) -#undef MAX -#define MAX(a,b) ((a)>(b) ? (a) : (b)) - -struct FIO_display_prefs_s { - int displayLevel; /* 0 : no display; 1: errors; 2: + result + interaction + warnings; 3: + progression; 4: + information */ - FIO_progressSetting_e progressSetting; -}; - -static FIO_display_prefs_t g_display_prefs = {2, FIO_ps_auto}; - -#define DISPLAY(...) fprintf(stderr, __VA_ARGS__) -#define DISPLAYOUT(...) fprintf(stdout, __VA_ARGS__) -#define DISPLAYLEVEL(l, ...) { if (g_display_prefs.displayLevel>=l) { DISPLAY(__VA_ARGS__); } } - -static const U64 g_refreshRate = SEC_TO_MICRO / 6; -static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER; - -#define READY_FOR_UPDATE() ((g_display_prefs.progressSetting != FIO_ps_never) && UTIL_clockSpanMicro(g_displayClock) > g_refreshRate) -#define DELAY_NEXT_UPDATE() { g_displayClock = UTIL_getTime(); } -#define DISPLAYUPDATE(l, ...) { \ - if (g_display_prefs.displayLevel>=l && (g_display_prefs.progressSetting != FIO_ps_never)) { \ - if (READY_FOR_UPDATE() || (g_display_prefs.displayLevel>=4)) { \ - DELAY_NEXT_UPDATE(); \ - DISPLAY(__VA_ARGS__); \ - if (g_display_prefs.displayLevel>=4) fflush(stderr); \ - } } } - -#undef MIN /* in case it would be already defined */ -#define MIN(a,b) ((a) < (b) ? (a) : (b)) - - -#define EXM_THROW(error, ...) \ -{ \ - DISPLAYLEVEL(1, "zstd: "); \ - DISPLAYLEVEL(5, "Error defined at %s, line %i : \n", __FILE__, __LINE__); \ - DISPLAYLEVEL(1, "error %i : ", error); \ - DISPLAYLEVEL(1, __VA_ARGS__); \ - DISPLAYLEVEL(1, " \n"); \ - exit(error); \ -} - -#define CHECK_V(v, f) \ - v = f; \ - if (ZSTD_isError(v)) { \ - DISPLAYLEVEL(5, "%s \n", #f); \ - EXM_THROW(11, "%s", ZSTD_getErrorName(v)); \ - } -#define CHECK(f) { size_t err; CHECK_V(err, f); } - - /*-************************************ * Signal (Ctrl-C trapping) **************************************/ @@ -250,95 +196,6 @@ void FIO_addAbortHandler() #endif } - -/*-************************************************************ -* Avoid fseek()'s 2GiB barrier with MSVC, macOS, *BSD, MinGW -***************************************************************/ -#if defined(_MSC_VER) && _MSC_VER >= 1400 -# define LONG_SEEK _fseeki64 -# define LONG_TELL _ftelli64 -#elif !defined(__64BIT__) && (PLATFORM_POSIX_VERSION >= 200112L) /* No point defining Large file for 64 bit */ -# define LONG_SEEK fseeko -# define LONG_TELL ftello -#elif defined(__MINGW32__) && !defined(__STRICT_ANSI__) && !defined(__NO_MINGW_LFS) && defined(__MSVCRT__) -# define LONG_SEEK fseeko64 -# define LONG_TELL ftello64 -#elif defined(_WIN32) && !defined(__DJGPP__) -# include - static int LONG_SEEK(FILE* file, __int64 offset, int origin) { - LARGE_INTEGER off; - DWORD method; - off.QuadPart = offset; - if (origin == SEEK_END) - method = FILE_END; - else if (origin == SEEK_CUR) - method = FILE_CURRENT; - else - method = FILE_BEGIN; - - if (SetFilePointerEx((HANDLE) _get_osfhandle(_fileno(file)), off, NULL, method)) - return 0; - else - return -1; - } - static __int64 LONG_TELL(FILE* file) { - LARGE_INTEGER off, newOff; - off.QuadPart = 0; - newOff.QuadPart = 0; - SetFilePointerEx((HANDLE) _get_osfhandle(_fileno(file)), off, &newOff, FILE_CURRENT); - return newOff.QuadPart; - } -#else -# define LONG_SEEK fseek -# define LONG_TELL ftell -#endif - - -/*-************************************* -* Parameters: FIO_prefs_t -***************************************/ - -/* typedef'd to FIO_prefs_t within fileio.h */ -struct FIO_prefs_s { - - /* Algorithm preferences */ - FIO_compressionType_t compressionType; - U32 sparseFileSupport; /* 0: no sparse allowed; 1: auto (file yes, stdout no); 2: force sparse */ - int dictIDFlag; - int checksumFlag; - int blockSize; - int overlapLog; - U32 adaptiveMode; - U32 useRowMatchFinder; - int rsyncable; - int minAdaptLevel; - int maxAdaptLevel; - int ldmFlag; - int ldmHashLog; - int ldmMinMatch; - int ldmBucketSizeLog; - int ldmHashRateLog; - size_t streamSrcSize; - size_t targetCBlockSize; - int srcSizeHint; - int testMode; - ZSTD_paramSwitch_e literalCompressionMode; - - /* IO preferences */ - U32 removeSrcFile; - U32 overwrite; - U32 asyncIO; - - /* Computation resources preferences */ - unsigned memLimit; - int nbWorkers; - - int excludeCompressedFiles; - int patchFromMode; - int contentSize; - int allowBlockDevices; -}; - /*-************************************* * Parameters: FIO_ctx_t ***************************************/ @@ -563,7 +420,13 @@ void FIO_setContentSize(FIO_prefs_t* const prefs, int value) } void FIO_setAsyncIOFlag(FIO_prefs_t* const prefs, unsigned value) { +#ifdef ZSTD_MULTITHREAD prefs->asyncIO = value; +#else + (void) prefs; + (void) value; + DISPLAYLEVEL(2, "Note : asyncio is disabled (lack of multithreading support) \n"); +#endif } /* FIO_ctx_t functions */ @@ -2019,124 +1882,15 @@ int FIO_compressMultipleFilenames(FIO_ctx_t* const fCtx, /* ************************************************************************** * Decompression ***************************************************************************/ -#define DECOMPRESSION_MAX_WRITE_JOBS (10) - -typedef struct { - /* These struct fields should be set only on creation and not changed afterwards */ - POOL_ctx* writerPool; - int totalWriteJobs; - FIO_prefs_t* prefs; - - /* Controls the file we currently write to, make changes only by using provided utility functions */ - FILE* dstFile; - unsigned storedSkips; - - /* The jobs and availableWriteJobs fields are access by both the main and writer threads and should - * only be mutated after locking the mutex */ - ZSTD_pthread_mutex_t writeJobsMutex; - void* jobs[DECOMPRESSION_MAX_WRITE_JOBS]; - int availableWriteJobs; -} write_pool_ctx_t; - -typedef struct { - /* These fields are automaically set and shouldn't be changed by non WritePool code. */ - write_pool_ctx_t *ctx; - FILE* dstFile; - void *buffer; - size_t bufferSize; - - /* This field should be changed before a job is queued for execution and should contain the number - * of bytes to write from the buffer. */ - size_t usedBufferSize; -} write_job_t; typedef struct { void* srcBuffer; size_t srcBufferSize; size_t srcBufferLoaded; ZSTD_DStream* dctx; - write_pool_ctx_t *writePoolCtx; + write_pool_ctx_t *writeCtx; } dRess_t; -static write_job_t *FIO_createWriteJob(write_pool_ctx_t *ctx) { - void *buffer; - write_job_t *job; - job = (write_job_t*) malloc(sizeof(write_job_t)); - buffer = malloc(ZSTD_DStreamOutSize()); - if(!job || !buffer) - EXM_THROW(101, "Allocation error : not enough memory"); - job->buffer = buffer; - job->bufferSize = ZSTD_DStreamOutSize(); - job->usedBufferSize = 0; - job->dstFile = NULL; - job->ctx = ctx; - return job; -} - -/* WritePool_createThreadPool: - * Creates a thread pool and a mutex for threaded write pool. - * Displays warning if asyncio is requested but MT isn't available. */ -static void WritePool_createThreadPool(write_pool_ctx_t *ctx, const FIO_prefs_t *prefs) { - ctx->writerPool = NULL; - if(prefs->asyncIO) { -#ifdef ZSTD_MULTITHREAD - if (ZSTD_pthread_mutex_init(&ctx->writeJobsMutex, NULL)) - EXM_THROW(102, "Failed creating write jobs mutex"); - /* We want DECOMPRESSION_MAX_WRITE_JOBS-2 queue items because we need to always have 1 free buffer to - * decompress into and 1 buffer that's actively written to disk and owned by the writing thread. */ - assert(DECOMPRESSION_MAX_WRITE_JOBS >= 2); - ctx->writerPool = POOL_create(1, DECOMPRESSION_MAX_WRITE_JOBS - 2); - if (!ctx->writerPool) - EXM_THROW(103, "Failed creating writer thread pool"); -#else - DISPLAYLEVEL(2, "Note : asyncio decompression is disabled (lack of multithreading support) \n"); -#endif - } -} - -/* WritePool_create: - * Allocates and sets and a new write pool including its included jobs. */ -static write_pool_ctx_t* WritePool_create(FIO_prefs_t* const prefs) { - write_pool_ctx_t *ctx; - int i; - ctx = (write_pool_ctx_t*) malloc(sizeof(write_pool_ctx_t)); - if(!ctx) - EXM_THROW(100, "Allocation error : not enough memory"); - WritePool_createThreadPool(ctx, prefs); - ctx->prefs = prefs; - ctx->totalWriteJobs = ctx->writerPool ? DECOMPRESSION_MAX_WRITE_JOBS : 1; - ctx->availableWriteJobs = ctx->totalWriteJobs; - for(i=0; i < ctx->availableWriteJobs; i++) { - ctx->jobs[i] = FIO_createWriteJob(ctx); - } - ctx->storedSkips = 0; - ctx->dstFile = NULL; - return ctx; -} - -/* WritePool_free: - * Release a previously allocated write thread pool. Makes sure all takss are done and released. */ -static void WritePool_free(write_pool_ctx_t* ctx) { - int i=0; - if(ctx->writerPool) { - /* Make sure we finish all tasks and then free the resources */ - POOL_joinJobs(ctx->writerPool); - /* Make sure we are not leaking jobs */ - assert(ctx->availableWriteJobs==ctx->totalWriteJobs); - POOL_free(ctx->writerPool); - ZSTD_pthread_mutex_destroy(&ctx->writeJobsMutex); - } - assert(ctx->dstFile==NULL); - assert(ctx->storedSkips==0); - for(i=0; iavailableWriteJobs; i++) { - write_job_t* job = (write_job_t*) ctx->jobs[i]; - free(job->buffer); - free(job); - } - free(ctx); -} - - static dRess_t FIO_createDResources(FIO_prefs_t* const prefs, const char* dictFileName) { dRess_t ress; @@ -2164,7 +1918,7 @@ static dRess_t FIO_createDResources(FIO_prefs_t* const prefs, const char* dictFi free(dictBuffer); } - ress.writePoolCtx = WritePool_create(prefs); + ress.writeCtx = WritePool_create(prefs, ZSTD_DStreamOutSize()); return ress; } @@ -2173,7 +1927,7 @@ static void FIO_freeDResources(dRess_t ress) { CHECK( ZSTD_freeDStream(ress.dctx) ); free(ress.srcBuffer); - WritePool_free(ress.writePoolCtx); + WritePool_free(ress.writeCtx); } /* FIO_consumeDSrcBuffer: @@ -2184,205 +1938,6 @@ static void FIO_consumeDSrcBuffer(dRess_t *ress, size_t len) { memmove(ress->srcBuffer, (char *)ress->srcBuffer + len, ress->srcBufferLoaded); } -/** FIO_fwriteSparse() : -* @return : storedSkips, -* argument for next call to FIO_fwriteSparse() or FIO_fwriteSparseEnd() */ -static unsigned -FIO_fwriteSparse(FILE* file, - const void* buffer, size_t bufferSize, - const FIO_prefs_t* const prefs, - unsigned storedSkips) -{ - const size_t* const bufferT = (const size_t*)buffer; /* Buffer is supposed malloc'ed, hence aligned on size_t */ - size_t bufferSizeT = bufferSize / sizeof(size_t); - const size_t* const bufferTEnd = bufferT + bufferSizeT; - const size_t* ptrT = bufferT; - static const size_t segmentSizeT = (32 KB) / sizeof(size_t); /* check every 32 KB */ - - if (prefs->testMode) return 0; /* do not output anything in test mode */ - - if (!prefs->sparseFileSupport) { /* normal write */ - size_t const sizeCheck = fwrite(buffer, 1, bufferSize, file); - if (sizeCheck != bufferSize) - EXM_THROW(70, "Write error : cannot write decoded block : %s", - strerror(errno)); - return 0; - } - - /* avoid int overflow */ - if (storedSkips > 1 GB) { - if (LONG_SEEK(file, 1 GB, SEEK_CUR) != 0) - EXM_THROW(91, "1 GB skip error (sparse file support)"); - storedSkips -= 1 GB; - } - - while (ptrT < bufferTEnd) { - size_t nb0T; - - /* adjust last segment if < 32 KB */ - size_t seg0SizeT = segmentSizeT; - if (seg0SizeT > bufferSizeT) seg0SizeT = bufferSizeT; - bufferSizeT -= seg0SizeT; - - /* count leading zeroes */ - for (nb0T=0; (nb0T < seg0SizeT) && (ptrT[nb0T] == 0); nb0T++) ; - storedSkips += (unsigned)(nb0T * sizeof(size_t)); - - if (nb0T != seg0SizeT) { /* not all 0s */ - size_t const nbNon0ST = seg0SizeT - nb0T; - /* skip leading zeros */ - if (LONG_SEEK(file, storedSkips, SEEK_CUR) != 0) - EXM_THROW(92, "Sparse skip error ; try --no-sparse"); - storedSkips = 0; - /* write the rest */ - if (fwrite(ptrT + nb0T, sizeof(size_t), nbNon0ST, file) != nbNon0ST) - EXM_THROW(93, "Write error : cannot write decoded block : %s", - strerror(errno)); - } - ptrT += seg0SizeT; - } - - { static size_t const maskT = sizeof(size_t)-1; - if (bufferSize & maskT) { - /* size not multiple of sizeof(size_t) : implies end of block */ - const char* const restStart = (const char*)bufferTEnd; - const char* restPtr = restStart; - const char* const restEnd = (const char*)buffer + bufferSize; - assert(restEnd > restStart && restEnd < restStart + sizeof(size_t)); - for ( ; (restPtr < restEnd) && (*restPtr == 0); restPtr++) ; - storedSkips += (unsigned) (restPtr - restStart); - if (restPtr != restEnd) { - /* not all remaining bytes are 0 */ - size_t const restSize = (size_t)(restEnd - restPtr); - if (LONG_SEEK(file, storedSkips, SEEK_CUR) != 0) - EXM_THROW(92, "Sparse skip error ; try --no-sparse"); - if (fwrite(restPtr, 1, restSize, file) != restSize) - EXM_THROW(95, "Write error : cannot write end of decoded block : %s", - strerror(errno)); - storedSkips = 0; - } } } - - return storedSkips; -} - -static void -FIO_fwriteSparseEnd(const FIO_prefs_t* const prefs, FILE* file, unsigned storedSkips) -{ - if (prefs->testMode) assert(storedSkips == 0); - if (storedSkips>0) { - assert(prefs->sparseFileSupport > 0); /* storedSkips>0 implies sparse support is enabled */ - (void)prefs; /* assert can be disabled, in which case prefs becomes unused */ - if (LONG_SEEK(file, storedSkips-1, SEEK_CUR) != 0) - EXM_THROW(69, "Final skip error (sparse file support)"); - /* last zero must be explicitly written, - * so that skipped ones get implicitly translated as zero by FS */ - { const char lastZeroByte[1] = { 0 }; - if (fwrite(lastZeroByte, 1, 1, file) != 1) - EXM_THROW(69, "Write error : cannot write last zero : %s", strerror(errno)); - } } -} - -/* WritePool_releaseWriteJob: - * Releases an acquired job back to the pool. Doesn't execute the job. */ -static void WritePool_releaseWriteJob(write_job_t *job) { - write_pool_ctx_t *ctx = job->ctx; - if(ctx->writerPool) { - ZSTD_pthread_mutex_lock(&ctx->writeJobsMutex); - assert(ctx->availableWriteJobs < DECOMPRESSION_MAX_WRITE_JOBS); - ctx->jobs[ctx->availableWriteJobs++] = job; - ZSTD_pthread_mutex_unlock(&ctx->writeJobsMutex); - } else { - ctx->availableWriteJobs++; - } -} - -/* WritePool_acquireWriteJob: - * Returns an available write job to be used for a future write. */ -static write_job_t* WritePool_acquireWriteJob(write_pool_ctx_t *ctx) { - write_job_t *job; - assert(ctx->dstFile!=NULL || ctx->prefs->testMode); - if(ctx->writerPool) { - ZSTD_pthread_mutex_lock(&ctx->writeJobsMutex); - assert(ctx->availableWriteJobs > 0); - job = (write_job_t*) ctx->jobs[--ctx->availableWriteJobs]; - ZSTD_pthread_mutex_unlock(&ctx->writeJobsMutex); - } else { - assert(ctx->availableWriteJobs==1); - ctx->availableWriteJobs--; - job = (write_job_t*)ctx->jobs[0]; - } - job->usedBufferSize = 0; - job->dstFile = ctx->dstFile; - return job; -} - -/* WritePool_executeWriteJob: - * Executes a write job synchronously. Can be used as a function for a thread pool. */ -static void WritePool_executeWriteJob(void* opaque){ - write_job_t* job = (write_job_t*) opaque; - write_pool_ctx_t* ctx = job->ctx; - ctx->storedSkips = FIO_fwriteSparse(job->dstFile, job->buffer, job->usedBufferSize, ctx->prefs, ctx->storedSkips); - WritePool_releaseWriteJob(job); -} - -/* WritePool_queueWriteJob: - * Queues a write job for execution. - * Make sure to set `usedBufferSize` to the wanted length before call. - * The queued job shouldn't be used directly after queueing it. */ -static void WritePool_queueWriteJob(write_job_t *job) { - write_pool_ctx_t* ctx = job->ctx; - if(ctx->writerPool) - POOL_add(ctx->writerPool, WritePool_executeWriteJob, job); - else - WritePool_executeWriteJob(job); -} - -/* WritePool_queueAndReacquireWriteJob: - * Queues a write job for execution and acquires a new one. - * After execution `job`'s pointed value would change to the newly acquired job. - * Make sure to set `usedBufferSize` to the wanted length before call. - * The queued job shouldn't be used directly after queueing it. */ -static void WritePool_queueAndReacquireWriteJob(write_job_t **job) { - WritePool_queueWriteJob(*job); - *job = WritePool_acquireWriteJob((*job)->ctx); -} - -/* WritePool_sparseWriteEnd: - * Ends sparse writes to the current dstFile. - * Blocks on completion of all current write jobs before executing. */ -static void WritePool_sparseWriteEnd(write_pool_ctx_t* ctx) { - assert(ctx != NULL); - if(ctx->writerPool) - POOL_joinJobs(ctx->writerPool); - FIO_fwriteSparseEnd(ctx->prefs, ctx->dstFile, ctx->storedSkips); - ctx->storedSkips = 0; -} - -/* WritePool_setDstFile: - * Sets the destination file for future files in the pool. - * Requires completion of all queues write jobs and release of all otherwise acquired jobs. - * Also requires ending of sparse write if a previous file was used in sparse mode. */ -static void WritePool_setDstFile(write_pool_ctx_t *ctx, FILE* dstFile) { - assert(ctx!=NULL); - /* We can change the dst file only if we have finished writing */ - if(ctx->writerPool) - POOL_joinJobs(ctx->writerPool); - assert(ctx->storedSkips == 0); - assert(ctx->availableWriteJobs == ctx->totalWriteJobs); - ctx->dstFile = dstFile; -} - -/* WritePool_closeDstFile: - * Ends sparse write and closes the writePool's current dstFile and sets the dstFile to NULL. - * Requires completion of all queues write jobs and release of all otherwise acquired jobs. */ -static int WritePool_closeDstFile(write_pool_ctx_t *ctx) { - FILE *dstFile = ctx->dstFile; - assert(dstFile!=NULL || ctx->prefs->testMode!=0); - WritePool_sparseWriteEnd(ctx); - WritePool_setDstFile(ctx, NULL); - return fclose(dstFile); -} - /** FIO_passThrough() : just copy input into output, for compatibility with gzip -df mode @return : 0 (no error) */ static int FIO_passThrough(const FIO_prefs_t* const prefs, @@ -2458,7 +2013,7 @@ FIO_decompressZstdFrame(FIO_ctx_t* const fCtx, dRess_t* ress, FILE* finput, U64 alreadyDecoded) /* for multi-frames streams */ { U64 frameSize = 0; - write_job_t *writeJob = WritePool_acquireWriteJob(ress->writePoolCtx); + io_job_t *writeJob = WritePool_acquireJob(ress->writeCtx); /* display last 20 characters only */ { size_t const srcFileLength = strlen(srcFileName); @@ -2486,12 +2041,13 @@ FIO_decompressZstdFrame(FIO_ctx_t* const fCtx, dRess_t* ress, FILE* finput, DISPLAYLEVEL(1, "%s : Decoding error (36) : %s \n", srcFileName, ZSTD_getErrorName(readSizeHint)); FIO_zstdErrorHelp(prefs, ress, readSizeHint, srcFileName); + WritePool_releaseIoJob(writeJob); return FIO_ERROR_FRAME_DECODING; } /* Write block */ writeJob->usedBufferSize = outBuff.pos; - WritePool_queueAndReacquireWriteJob(&writeJob); + WritePool_enqueueAndReacquireWriteJob(&writeJob); frameSize += outBuff.pos; if (fCtx->nbFilesTotal > 1) { size_t srcFileNameSize = strlen(srcFileName); @@ -2526,8 +2082,8 @@ FIO_decompressZstdFrame(FIO_ctx_t* const fCtx, dRess_t* ress, FILE* finput, ress->srcBufferLoaded += readSize; } } } - WritePool_releaseWriteJob(writeJob); - WritePool_sparseWriteEnd(ress->writePoolCtx); + WritePool_releaseIoJob(writeJob); + WritePool_sparseWriteEnd(ress->writeCtx); return frameSize; } @@ -2541,7 +2097,7 @@ FIO_decompressGzFrame(dRess_t* ress, FILE* srcFile, const char* srcFileName) z_stream strm; int flush = Z_NO_FLUSH; int decodingError = 0; - write_job_t *writeJob = NULL; + io_job_t *writeJob = NULL; strm.zalloc = Z_NULL; strm.zfree = Z_NULL; @@ -2552,7 +2108,7 @@ FIO_decompressGzFrame(dRess_t* ress, FILE* srcFile, const char* srcFileName) if (inflateInit2(&strm, 15 /* maxWindowLogSize */ + 16 /* gzip only */) != Z_OK) return FIO_ERROR_FRAME_DECODING; - writeJob = WritePool_acquireWriteJob(ress->writePoolCtx); + writeJob = WritePool_acquireJob(ress->writeCtx); strm.next_out = (Bytef*)writeJob->buffer; strm.avail_out = (uInt)writeJob->bufferSize; strm.avail_in = (uInt)ress->srcBufferLoaded; @@ -2578,7 +2134,7 @@ FIO_decompressGzFrame(dRess_t* ress, FILE* srcFile, const char* srcFileName) { size_t const decompBytes = writeJob->bufferSize - strm.avail_out; if (decompBytes) { writeJob->usedBufferSize = decompBytes; - WritePool_queueAndReacquireWriteJob(&writeJob); + WritePool_enqueueAndReacquireWriteJob(&writeJob); outFileSize += decompBytes; strm.next_out = (Bytef*)writeJob->buffer; strm.avail_out = (uInt)writeJob->bufferSize; @@ -2594,8 +2150,8 @@ FIO_decompressGzFrame(dRess_t* ress, FILE* srcFile, const char* srcFileName) DISPLAYLEVEL(1, "zstd: %s: inflateEnd error \n", srcFileName); decodingError = 1; } - WritePool_releaseWriteJob(writeJob); - WritePool_sparseWriteEnd(ress->writePoolCtx); + WritePool_releaseIoJob(writeJob); + WritePool_sparseWriteEnd(ress->writeCtx); return decodingError ? FIO_ERROR_FRAME_DECODING : outFileSize; } #endif @@ -2610,7 +2166,7 @@ FIO_decompressLzmaFrame(dRess_t* ress, FILE* srcFile, lzma_action action = LZMA_RUN; lzma_ret initRet; int decodingError = 0; - write_job_t *writeJob = NULL; + io_job_t *writeJob = NULL; strm.next_in = 0; strm.avail_in = 0; @@ -2627,7 +2183,7 @@ FIO_decompressLzmaFrame(dRess_t* ress, FILE* srcFile, return FIO_ERROR_FRAME_DECODING; } - writeJob = WritePool_acquireWriteJob(ress->writePoolCtx); + writeJob = WritePool_acquireJob(ress->writeCtx); strm.next_out = (Bytef*)writeJob->buffer; strm.avail_out = (uInt)writeJob->bufferSize; strm.next_in = (BYTE const*)ress->srcBuffer; @@ -2655,7 +2211,7 @@ FIO_decompressLzmaFrame(dRess_t* ress, FILE* srcFile, { size_t const decompBytes = writeJob->bufferSize - strm.avail_out; if (decompBytes) { writeJob->usedBufferSize = decompBytes; - WritePool_queueAndReacquireWriteJob(&writeJob); + WritePool_enqueueAndReacquireWriteJob(&writeJob); outFileSize += decompBytes; strm.next_out = (Bytef*)writeJob->buffer; strm.avail_out = writeJob->bufferSize; @@ -2665,8 +2221,8 @@ FIO_decompressLzmaFrame(dRess_t* ress, FILE* srcFile, FIO_consumeDSrcBuffer(ress, ress->srcBufferLoaded - strm.avail_in); lzma_end(&strm); - WritePool_releaseWriteJob(writeJob); - WritePool_sparseWriteEnd(ress->writePoolCtx); + WritePool_releaseIoJob(writeJob); + WritePool_sparseWriteEnd(ress->writeCtx); return decodingError ? FIO_ERROR_FRAME_DECODING : outFileSize; } #endif @@ -2681,13 +2237,15 @@ FIO_decompressLz4Frame(dRess_t* ress, FILE* srcFile, LZ4F_decompressionContext_t dCtx; LZ4F_errorCode_t const errorCode = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION); int decodingError = 0; - write_job_t *writeJob = WritePool_acquireWriteJob(ress->writePoolCtx); + io_job_t *writeJob = NULL; if (LZ4F_isError(errorCode)) { DISPLAYLEVEL(1, "zstd: failed to create lz4 decompression context \n"); return FIO_ERROR_FRAME_DECODING; } + writeJob = WritePool_acquireJob(ress->writeCtx); + /* Main Loop */ for (;nextToLoad;) { size_t readSize; @@ -2724,7 +2282,7 @@ FIO_decompressLz4Frame(dRess_t* ress, FILE* srcFile, if (decodedBytes) { UTIL_HumanReadableSize_t hrs; writeJob->usedBufferSize = decodedBytes; - WritePool_queueAndReacquireWriteJob(&writeJob); + WritePool_enqueueAndReacquireWriteJob(&writeJob); filesize += decodedBytes; hrs = UTIL_makeHumanReadableSize(filesize); DISPLAYUPDATE(2, "\rDecompressed : %.*f%s ", hrs.precision, hrs.value, hrs.suffix); @@ -2740,8 +2298,8 @@ FIO_decompressLz4Frame(dRess_t* ress, FILE* srcFile, } LZ4F_freeDecompressionContext(dCtx); - WritePool_releaseWriteJob(writeJob); - WritePool_sparseWriteEnd(ress->writePoolCtx); + WritePool_releaseIoJob(writeJob); + WritePool_sparseWriteEnd(ress->writeCtx); return decodingError ? FIO_ERROR_FRAME_DECODING : filesize; } @@ -2818,7 +2376,7 @@ static int FIO_decompressFrames(FIO_ctx_t* const fCtx, #endif } else if ((prefs->overwrite) && !strcmp (dstFileName, stdoutmark)) { /* pass-through mode */ return FIO_passThrough(prefs, - ress.writePoolCtx->dstFile, srcFile, + WritePool_getFile(ress.writeCtx), srcFile, ress.srcBuffer, ress.srcBufferSize, ress.srcBufferLoaded); } else { @@ -2856,7 +2414,7 @@ static int FIO_decompressDstFile(FIO_ctx_t* const fCtx, int releaseDstFile = 0; int transferMTime = 0; - if ((ress.writePoolCtx->dstFile == NULL) && (prefs->testMode==0)) { + if ((WritePool_getFile(ress.writeCtx) == NULL) && (prefs->testMode == 0)) { FILE *dstFile; int dstFilePermissions = DEFAULT_FILE_PERMISSIONS; if ( strcmp(srcFileName, stdinmark) /* special case : don't transfer permissions from stdin */ @@ -2871,7 +2429,7 @@ static int FIO_decompressDstFile(FIO_ctx_t* const fCtx, dstFile = FIO_openDstFile(fCtx, prefs, srcFileName, dstFileName, dstFilePermissions); if (dstFile==NULL) return 1; - WritePool_setDstFile(ress.writePoolCtx, dstFile); + WritePool_setFile(ress.writeCtx, dstFile); /* Must only be added after FIO_openDstFile() succeeds. * Otherwise we may delete the destination file if it already exists, @@ -2884,7 +2442,7 @@ static int FIO_decompressDstFile(FIO_ctx_t* const fCtx, if (releaseDstFile) { clearHandler(); - if (WritePool_closeDstFile(ress.writePoolCtx)) { + if (WritePool_closeFile(ress.writeCtx)) { DISPLAYLEVEL(1, "zstd: %s: %s \n", dstFileName, strerror(errno)); result = 1; } @@ -3100,14 +2658,14 @@ FIO_decompressMultipleFilenames(FIO_ctx_t* const fCtx, if (!prefs->testMode) { FILE* dstFile = FIO_openDstFile(fCtx, prefs, NULL, outFileName, DEFAULT_FILE_PERMISSIONS); if (dstFile == 0) EXM_THROW(19, "cannot open %s", outFileName); - WritePool_setDstFile(ress.writePoolCtx, dstFile); + WritePool_setFile(ress.writeCtx, dstFile); } for (; fCtx->currFileIdx < fCtx->nbFilesTotal; fCtx->currFileIdx++) { status = FIO_decompressSrcFile(fCtx, prefs, ress, outFileName, srcNamesTable[fCtx->currFileIdx]); if (!status) fCtx->nbFilesProcessed++; error |= status; } - if ((!prefs->testMode) && (WritePool_closeDstFile(ress.writePoolCtx))) + if ((!prefs->testMode) && (WritePool_closeFile(ress.writeCtx))) EXM_THROW(72, "Write error : %s : cannot properly close output file", strerror(errno)); } else { diff --git a/programs/fileio.h b/programs/fileio.h index 398937a64e8..9d6ebb1accb 100644 --- a/programs/fileio.h +++ b/programs/fileio.h @@ -13,6 +13,7 @@ #define FILEIO_H_23981798732 #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_compressionParameters */ +#include "fileio_types.h" #include "../lib/zstd.h" /* ZSTD_* */ #if defined (__cplusplus) @@ -53,10 +54,6 @@ extern "C" { /*-************************************* * Types ***************************************/ -typedef enum { FIO_zstdCompression, FIO_gzipCompression, FIO_xzCompression, FIO_lzmaCompression, FIO_lz4Compression } FIO_compressionType_t; - -typedef struct FIO_prefs_s FIO_prefs_t; - FIO_prefs_t* FIO_createPreferences(void); void FIO_freePreferences(FIO_prefs_t* const prefs); @@ -66,9 +63,6 @@ typedef struct FIO_ctx_s FIO_ctx_t; FIO_ctx_t* FIO_createContext(void); void FIO_freeContext(FIO_ctx_t* const fCtx); -typedef struct FIO_display_prefs_s FIO_display_prefs_t; - -typedef enum { FIO_ps_auto, FIO_ps_never, FIO_ps_always } FIO_progressSetting_e; /*-************************************* * Parameters diff --git a/programs/fileio_asycio.c b/programs/fileio_asycio.c new file mode 100644 index 00000000000..4bb2808b75f --- /dev/null +++ b/programs/fileio_asycio.c @@ -0,0 +1,355 @@ +#include "platform.h" +#include /* fprintf, open, fdopen, fread, _fileno, stdin, stdout */ +#include /* malloc, free */ +#include +#include /* errno */ + +#if defined (_MSC_VER) +# include +# include +#endif + +#include "fileio_asycio.h" +#include "fileio_common.h" + +/* ********************************************************************** + * Sparse write + ************************************************************************/ + +/** FIO_fwriteSparse() : +* @return : storedSkips, +* argument for next call to FIO_fwriteSparse() or FIO_fwriteSparseEnd() */ +unsigned FIO_fwriteSparse(FILE* file, + const void* buffer, size_t bufferSize, + const FIO_prefs_t* const prefs, + unsigned storedSkips) +{ + const size_t* const bufferT = (const size_t*)buffer; /* Buffer is supposed malloc'ed, hence aligned on size_t */ + size_t bufferSizeT = bufferSize / sizeof(size_t); + const size_t* const bufferTEnd = bufferT + bufferSizeT; + const size_t* ptrT = bufferT; + static const size_t segmentSizeT = (32 KB) / sizeof(size_t); /* check every 32 KB */ + + if (prefs->testMode) return 0; /* do not output anything in test mode */ + + if (!prefs->sparseFileSupport) { /* normal write */ + size_t const sizeCheck = fwrite(buffer, 1, bufferSize, file); + if (sizeCheck != bufferSize) + EXM_THROW(70, "Write error : cannot write decoded block : %s", + strerror(errno)); + return 0; + } + + /* avoid int overflow */ + if (storedSkips > 1 GB) { + if (LONG_SEEK(file, 1 GB, SEEK_CUR) != 0) + EXM_THROW(91, "1 GB skip error (sparse file support)"); + storedSkips -= 1 GB; + } + + while (ptrT < bufferTEnd) { + size_t nb0T; + + /* adjust last segment if < 32 KB */ + size_t seg0SizeT = segmentSizeT; + if (seg0SizeT > bufferSizeT) seg0SizeT = bufferSizeT; + bufferSizeT -= seg0SizeT; + + /* count leading zeroes */ + for (nb0T=0; (nb0T < seg0SizeT) && (ptrT[nb0T] == 0); nb0T++) ; + storedSkips += (unsigned)(nb0T * sizeof(size_t)); + + if (nb0T != seg0SizeT) { /* not all 0s */ + size_t const nbNon0ST = seg0SizeT - nb0T; + /* skip leading zeros */ + if (LONG_SEEK(file, storedSkips, SEEK_CUR) != 0) + EXM_THROW(92, "Sparse skip error ; try --no-sparse"); + storedSkips = 0; + /* write the rest */ + if (fwrite(ptrT + nb0T, sizeof(size_t), nbNon0ST, file) != nbNon0ST) + EXM_THROW(93, "Write error : cannot write decoded block : %s", + strerror(errno)); + } + ptrT += seg0SizeT; + } + + { static size_t const maskT = sizeof(size_t)-1; + if (bufferSize & maskT) { + /* size not multiple of sizeof(size_t) : implies end of block */ + const char* const restStart = (const char*)bufferTEnd; + const char* restPtr = restStart; + const char* const restEnd = (const char*)buffer + bufferSize; + assert(restEnd > restStart && restEnd < restStart + sizeof(size_t)); + for ( ; (restPtr < restEnd) && (*restPtr == 0); restPtr++) ; + storedSkips += (unsigned) (restPtr - restStart); + if (restPtr != restEnd) { + /* not all remaining bytes are 0 */ + size_t const restSize = (size_t)(restEnd - restPtr); + if (LONG_SEEK(file, storedSkips, SEEK_CUR) != 0) + EXM_THROW(92, "Sparse skip error ; try --no-sparse"); + if (fwrite(restPtr, 1, restSize, file) != restSize) + EXM_THROW(95, "Write error : cannot write end of decoded block : %s", + strerror(errno)); + storedSkips = 0; + } } } + + return storedSkips; +} + +void FIO_fwriteSparseEnd(const FIO_prefs_t* const prefs, FILE* file, unsigned storedSkips) +{ + if (prefs->testMode) assert(storedSkips == 0); + if (storedSkips>0) { + assert(prefs->sparseFileSupport > 0); /* storedSkips>0 implies sparse support is enabled */ + (void)prefs; /* assert can be disabled, in which case prefs becomes unused */ + if (LONG_SEEK(file, storedSkips-1, SEEK_CUR) != 0) + EXM_THROW(69, "Final skip error (sparse file support)"); + /* last zero must be explicitly written, + * so that skipped ones get implicitly translated as zero by FS */ + { const char lastZeroByte[1] = { 0 }; + if (fwrite(lastZeroByte, 1, 1, file) != 1) + EXM_THROW(69, "Write error : cannot write last zero : %s", strerror(errno)); + } } +} + + +/* ********************************************************************** + * AsyncIO functionality + ************************************************************************/ + +/* *********************************** + * General IoPool implementation + *************************************/ + +static io_job_t *IoPool_createIoJob(io_pool_ctx_t *ctx, size_t bufferSize) { + void *buffer; + io_job_t *job; + job = (io_job_t*) malloc(sizeof(io_job_t)); + buffer = malloc(bufferSize); + if(!job || !buffer) + EXM_THROW(101, "Allocation error : not enough memory"); + job->buffer = buffer; + job->bufferSize = bufferSize; + job->usedBufferSize = 0; + job->file = NULL; + job->ctx = ctx; + job->offset = 0; + return job; +} + + +/* IoPool_createThreadPool: + * Creates a thread pool and a mutex for threaded IO pool. + * Displays warning if asyncio is requested but MT isn't available. */ +static void IoPool_createThreadPool(io_pool_ctx_t *ctx, const FIO_prefs_t *prefs) { + ctx->threadPool = NULL; + if(prefs->asyncIO) { + if (ZSTD_pthread_mutex_init(&ctx->ioJobsMutex, NULL)) + EXM_THROW(102,"Failed creating write availableJobs mutex"); + /* We want MAX_IO_JOBS-2 queue items because we need to always have 1 free buffer to + * decompress into and 1 buffer that's actively written to disk and owned by the writing thread. */ + assert(MAX_IO_JOBS >= 2); + ctx->threadPool = POOL_create(1, MAX_IO_JOBS - 2); + if (!ctx->threadPool) + EXM_THROW(104, "Failed creating writer thread pool"); + } +} + +/* IoPool_init: + * Allocates and sets and a new write pool including its included availableJobs. */ +static void IoPool_init(io_pool_ctx_t *ctx, FIO_prefs_t* const prefs, POOL_function poolFunction, size_t bufferSize) { + int i; + IoPool_createThreadPool(ctx, prefs); + ctx->prefs = prefs; + ctx->poolFunction = poolFunction; + ctx->totalIoJobs = ctx->threadPool ? MAX_IO_JOBS : 1; + ctx->availableJobsCount = ctx->totalIoJobs; + for(i=0; i < ctx->availableJobsCount; i++) { + ctx->availableJobs[i] = IoPool_createIoJob(ctx, bufferSize); + } + ctx->file = NULL; +} + + +/* IoPool_releaseIoJob: + * Releases an acquired job back to the pool. Doesn't execute the job. */ +static void IoPool_releaseIoJob(io_job_t *job) { + io_pool_ctx_t *ctx = (io_pool_ctx_t *) job->ctx; + if(ctx->threadPool) { + ZSTD_pthread_mutex_lock(&ctx->ioJobsMutex); + assert(ctx->availableJobsCount < MAX_IO_JOBS); + ctx->availableJobs[ctx->availableJobsCount++] = job; + ZSTD_pthread_mutex_unlock(&ctx->ioJobsMutex); + } else { + assert(ctx->availableJobsCount == 0); + ctx->availableJobsCount++; + } +} + +/* IoPool_join: + * Waits for all tasks in the pool to finish executing. */ +static void IoPool_join(io_pool_ctx_t* ctx) { + if(ctx->threadPool) + POOL_joinJobs(ctx->threadPool); +} + +/* IoPool_free: + * Release a previously allocated write thread pool. Makes sure all takss are done and released. */ +static void IoPool_destroy(io_pool_ctx_t* ctx) { + int i; + if(ctx->threadPool) { + /* Make sure we finish all tasks and then free the resources */ + IoPool_join(ctx); + /* Make sure we are not leaking availableJobs */ + assert(ctx->availableJobsCount == ctx->totalIoJobs); + POOL_free(ctx->threadPool); + ZSTD_pthread_mutex_destroy(&ctx->ioJobsMutex); + } + assert(ctx->file == NULL); + for(i=0; iavailableJobsCount; i++) { + io_job_t* job = (io_job_t*) ctx->availableJobs[i]; + free(job->buffer); + free(job); + } +} + +/* IoPool_acquireJob: + * Returns an available io job to be used for a future io. */ +static io_job_t* IoPool_acquireJob(io_pool_ctx_t *ctx) { + io_job_t *job; + assert(ctx->file != NULL || ctx->prefs->testMode); + if(ctx->threadPool) { + ZSTD_pthread_mutex_lock(&ctx->ioJobsMutex); + assert(ctx->availableJobsCount > 0); + job = (io_job_t*) ctx->availableJobs[--ctx->availableJobsCount]; + ZSTD_pthread_mutex_unlock(&ctx->ioJobsMutex); + } else { + assert(ctx->availableJobsCount == 1); + ctx->availableJobsCount--; + job = (io_job_t*)ctx->availableJobs[0]; + } + job->usedBufferSize = 0; + job->file = ctx->file; + job->offset = 0; + return job; +} + + +/* IoPool_setFile: + * Sets the destination file for future files in the pool. + * Requires completion of all queues write jobs and release of all otherwise acquired jobs. + * Also requires ending of sparse write if a previous file was used in sparse mode. */ +static void IoPool_setFile(io_pool_ctx_t *ctx, FILE* file) { + assert(ctx!=NULL); + IoPool_join(ctx); + assert(ctx->availableJobsCount == ctx->totalIoJobs); + ctx->file = file; +} + +static FILE* IoPool_getFile(io_pool_ctx_t *ctx) { + return ctx->file; +} + +/* IoPool_enqueueJob: + * Enqueues an io job for execution. + * The queued job shouldn't be used directly after queueing it. */ +static void IoPool_enqueueJob(io_job_t *job) { + io_pool_ctx_t* ctx = (io_pool_ctx_t *)job->ctx; + if(ctx->threadPool) + POOL_add(ctx->threadPool, ctx->poolFunction, job); + else + ctx->poolFunction(job); +} + +/* *********************************** + * WritePool implementation + *************************************/ + +/* WritePool_acquireJob: + * Returns an available write job to be used for a future write. */ +io_job_t* WritePool_acquireJob(write_pool_ctx_t *ctx) { + return IoPool_acquireJob(&ctx->base); +} + +/* WritePool_enqueueAndReacquireWriteJob: + * Queues a write job for execution and acquires a new one. + * After execution `job`'s pointed value would change to the newly acquired job. + * Make sure to set `usedBufferSize` to the wanted length before call. + * The queued job shouldn't be used directly after queueing it. */ +void WritePool_enqueueAndReacquireWriteJob(io_job_t **job) { + IoPool_enqueueJob(*job); + *job = IoPool_acquireJob((io_pool_ctx_t *)(*job)->ctx); +} + +/* WritePool_sparseWriteEnd: + * Ends sparse writes to the current file. + * Blocks on completion of all current write jobs before executing. */ +void WritePool_sparseWriteEnd(write_pool_ctx_t *ctx) { + assert(ctx != NULL); + if(ctx->base.threadPool) + POOL_joinJobs(ctx->base.threadPool); + FIO_fwriteSparseEnd(ctx->base.prefs, ctx->base.file, ctx->storedSkips); + ctx->storedSkips = 0; +} + +/* WritePool_setFile: + * Sets the destination file for future writes in the pool. + * Requires completion of all queues write jobs and release of all otherwise acquired jobs. + * Also requires ending of sparse write if a previous file was used in sparse mode. */ +void WritePool_setFile(write_pool_ctx_t *ctx, FILE* file) { + IoPool_setFile(&ctx->base, file); + assert(ctx->storedSkips == 0); +} + +/* WritePool_getFile: + * Returns the file the writePool is currently set to write to. */ +FILE* WritePool_getFile(write_pool_ctx_t *ctx) { + return IoPool_getFile(&ctx->base); +} + +/* WritePool_releaseIoJob: + * Releases an acquired job back to the pool. Doesn't execute the job. */ +void WritePool_releaseIoJob(io_job_t *job) { + IoPool_releaseIoJob(job); +} + +/* WritePool_closeFile: + * Ends sparse write and closes the writePool's current file and sets the file to NULL. + * Requires completion of all queues write jobs and release of all otherwise acquired jobs. */ +int WritePool_closeFile(write_pool_ctx_t *ctx) { + FILE *dstFile = ctx->base.file; + assert(dstFile!=NULL || ctx->base.prefs->testMode!=0); + WritePool_sparseWriteEnd(ctx); + IoPool_setFile(&ctx->base, NULL); + return fclose(dstFile); +} + +/* WritePool_executeWriteJob: + * Executes a write job synchronously. Can be used as a function for a thread pool. */ +static void WritePool_executeWriteJob(void* opaque){ + io_job_t* job = (io_job_t*) opaque; + write_pool_ctx_t* ctx = (write_pool_ctx_t*) job->ctx; + ctx->storedSkips = FIO_fwriteSparse(job->file, job->buffer, job->usedBufferSize, ctx->base.prefs, ctx->storedSkips); + IoPool_releaseIoJob(job); +} + +/* WritePool_create: + * Allocates and sets and a new write pool including its included jobs. */ +write_pool_ctx_t* WritePool_create(FIO_prefs_t* const prefs, size_t bufferSize) { + write_pool_ctx_t* ctx = (write_pool_ctx_t*) malloc(sizeof(write_pool_ctx_t)); + if(!ctx) EXM_THROW(100, "Allocation error : not enough memory"); + IoPool_init(&ctx->base, prefs, WritePool_executeWriteJob, bufferSize); + ctx->storedSkips = 0; + return ctx; +} + +/* WritePool_free: + * Frees and releases a writePool and its resources. Closes destination file if needs to. */ +void WritePool_free(write_pool_ctx_t* ctx) { + /* Make sure we finish all tasks and then free the resources */ + if(WritePool_getFile(ctx)) + WritePool_closeFile(ctx); + IoPool_destroy(&ctx->base); + assert(ctx->storedSkips==0); + free(ctx); +} diff --git a/programs/fileio_asycio.h b/programs/fileio_asycio.h new file mode 100644 index 00000000000..65cee434442 --- /dev/null +++ b/programs/fileio_asycio.h @@ -0,0 +1,110 @@ +#ifndef ZSTD_FILEIO_ASYNCIO_H +#define ZSTD_FILEIO_ASYNCIO_H + +#if defined (__cplusplus) +extern "C" { +#endif + +#include "../lib/common/mem.h" /* U32, U64 */ +#include "fileio_types.h" +#include "platform.h" +#include "util.h" +#include "../lib/common/pool.h" +#include "../lib/common/threading.h" + +#define MAX_IO_JOBS (10) + +typedef struct { + /* These struct fields should be set only on creation and not changed afterwards */ + POOL_ctx* threadPool; + int totalIoJobs; + FIO_prefs_t* prefs; + POOL_function poolFunction; + + /* Controls the file we currently write to, make changes only by using provided utility functions */ + FILE* file; + + /* The jobs and availableJobsCount fields are accessed by both the main and worker threads and should + * only be mutated after locking the mutex */ + ZSTD_pthread_mutex_t ioJobsMutex; + void* availableJobs[MAX_IO_JOBS]; + int availableJobsCount; +} io_pool_ctx_t; + +typedef struct { + io_pool_ctx_t base; + unsigned storedSkips; +} write_pool_ctx_t; + +typedef struct { + /* These fields are automatically set and shouldn't be changed by non WritePool code. */ + void *ctx; + FILE* file; + void *buffer; + size_t bufferSize; + + /* This field should be changed before a job is queued for execution and should contain the number + * of bytes to write from the buffer. */ + size_t usedBufferSize; + U64 offset; +} io_job_t; + +/** FIO_fwriteSparse() : +* @return : storedSkips, +* argument for next call to FIO_fwriteSparse() or FIO_fwriteSparseEnd() */ +unsigned FIO_fwriteSparse(FILE* file, + const void* buffer, size_t bufferSize, + const FIO_prefs_t* const prefs, + unsigned storedSkips); + +void FIO_fwriteSparseEnd(const FIO_prefs_t* const prefs, FILE* file, unsigned storedSkips); + +/* WritePool_releaseIoJob: + * Releases an acquired job back to the pool. Doesn't execute the job. */ +void WritePool_releaseIoJob(io_job_t *job); + +/* WritePool_acquireJob: + * Returns an available write job to be used for a future write. */ +io_job_t* WritePool_acquireJob(write_pool_ctx_t *ctx); + +/* WritePool_enqueueAndReacquireWriteJob: + * Enqueues a write job for execution and acquires a new one. + * After execution `job`'s pointed value would change to the newly acquired job. + * Make sure to set `usedBufferSize` to the wanted length before call. + * The queued job shouldn't be used directly after queueing it. */ +void WritePool_enqueueAndReacquireWriteJob(io_job_t **job); + +/* WritePool_sparseWriteEnd: + * Ends sparse writes to the current file. + * Blocks on completion of all current write jobs before executing. */ +void WritePool_sparseWriteEnd(write_pool_ctx_t *ctx); + +/* WritePool_setFile: + * Sets the destination file for future writes in the pool. + * Requires completion of all queues write jobs and release of all otherwise acquired jobs. + * Also requires ending of sparse write if a previous file was used in sparse mode. */ +void WritePool_setFile(write_pool_ctx_t *ctx, FILE* file); + +/* WritePool_getFile: + * Returns the file the writePool is currently set to write to. */ +FILE* WritePool_getFile(write_pool_ctx_t *ctx); + +/* WritePool_closeFile: + * Ends sparse write and closes the writePool's current file and sets the file to NULL. + * Requires completion of all queues write jobs and release of all otherwise acquired jobs. */ +int WritePool_closeFile(write_pool_ctx_t *ctx); + +/* WritePool_create: + * Allocates and sets and a new write pool including its included jobs. + * bufferSize should be set to the maximal buffer we want to write to at a time. */ +write_pool_ctx_t* WritePool_create(FIO_prefs_t* const prefs, size_t bufferSize); + +/* WritePool_free: + * Frees and releases a writePool and its resources. Closes destination file. */ +void WritePool_free(write_pool_ctx_t* ctx); + +#if defined (__cplusplus) +} +#endif + +#endif /* ZSTD_FILEIO_ASYNCIO_H */ diff --git a/programs/fileio_common.h b/programs/fileio_common.h new file mode 100644 index 00000000000..d5bb1d0c19b --- /dev/null +++ b/programs/fileio_common.h @@ -0,0 +1,107 @@ +#ifndef ZSTD_FILEIO_COMMON_H +#define ZSTD_FILEIO_COMMON_H + +#if defined (__cplusplus) +extern "C" { +#endif + +#include "../lib/common/mem.h" /* U32, U64 */ +#include "fileio_types.h" +#include "platform.h" +#include "timefn.h" /* UTIL_getTime, UTIL_clockSpanMicro */ + +/*-************************************* +* Macros +***************************************/ +#define KB *(1 <<10) +#define MB *(1 <<20) +#define GB *(1U<<30) +#undef MAX +#define MAX(a,b) ((a)>(b) ? (a) : (b)) + +extern FIO_display_prefs_t g_display_prefs; + +#define DISPLAY(...) fprintf(stderr, __VA_ARGS__) +#define DISPLAYOUT(...) fprintf(stdout, __VA_ARGS__) +#define DISPLAYLEVEL(l, ...) { if (g_display_prefs.displayLevel>=l) { DISPLAY(__VA_ARGS__); } } + +extern UTIL_time_t g_displayClock; + +#define REFRESH_RATE ((U64)(SEC_TO_MICRO / 6)) +#define READY_FOR_UPDATE() ((g_display_prefs.progressSetting != FIO_ps_never) && UTIL_clockSpanMicro(g_displayClock) > REFRESH_RATE) +#define DELAY_NEXT_UPDATE() { g_displayClock = UTIL_getTime(); } +#define DISPLAYUPDATE(l, ...) { \ + if (g_display_prefs.displayLevel>=l && (g_display_prefs.progressSetting != FIO_ps_never)) { \ + if (READY_FOR_UPDATE() || (g_display_prefs.displayLevel>=4)) { \ + DELAY_NEXT_UPDATE(); \ + DISPLAY(__VA_ARGS__); \ + if (g_display_prefs.displayLevel>=4) fflush(stderr); \ + } } } + +#undef MIN /* in case it would be already defined */ +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + + +#define EXM_THROW(error, ...) \ +{ \ + DISPLAYLEVEL(1, "zstd: "); \ + DISPLAYLEVEL(5, "Error defined at %s, line %i : \n", __FILE__, __LINE__); \ + DISPLAYLEVEL(1, "error %i : ", error); \ + DISPLAYLEVEL(1, __VA_ARGS__); \ + DISPLAYLEVEL(1, " \n"); \ + exit(error); \ +} + +#define CHECK_V(v, f) \ + v = f; \ + if (ZSTD_isError(v)) { \ + DISPLAYLEVEL(5, "%s \n", #f); \ + EXM_THROW(11, "%s", ZSTD_getErrorName(v)); \ + } +#define CHECK(f) { size_t err; CHECK_V(err, f); } + + +/* Avoid fseek()'s 2GiB barrier with MSVC, macOS, *BSD, MinGW */ +#if defined(_MSC_VER) && _MSC_VER >= 1400 +# define LONG_SEEK _fseeki64 +# define LONG_TELL _ftelli64 +#elif !defined(__64BIT__) && (PLATFORM_POSIX_VERSION >= 200112L) /* No point defining Large file for 64 bit */ +# define LONG_SEEK fseeko +# define LONG_TELL ftello +#elif defined(__MINGW32__) && !defined(__STRICT_ANSI__) && !defined(__NO_MINGW_LFS) && defined(__MSVCRT__) +# define LONG_SEEK fseeko64 +# define LONG_TELL ftello64 +#elif defined(_WIN32) && !defined(__DJGPP__) +# include + static int LONG_SEEK(FILE* file, __int64 offset, int origin) { + LARGE_INTEGER off; + DWORD method; + off.QuadPart = offset; + if (origin == SEEK_END) + method = FILE_END; + else if (origin == SEEK_CUR) + method = FILE_CURRENT; + else + method = FILE_BEGIN; + + if (SetFilePointerEx((HANDLE) _get_osfhandle(_fileno(file)), off, NULL, method)) + return 0; + else + return -1; + } + static __int64 LONG_TELL(FILE* file) { + LARGE_INTEGER off, newOff; + off.QuadPart = 0; + newOff.QuadPart = 0; + SetFilePointerEx((HANDLE) _get_osfhandle(_fileno(file)), off, &newOff, FILE_CURRENT); + return newOff.QuadPart; + } +#else +# define LONG_SEEK fseek +# define LONG_TELL ftell +#endif + +#if defined (__cplusplus) +} +#endif +#endif //ZSTD_FILEIO_COMMON_H diff --git a/programs/fileio_types.h b/programs/fileio_types.h new file mode 100644 index 00000000000..80f55394fad --- /dev/null +++ b/programs/fileio_types.h @@ -0,0 +1,63 @@ +#ifndef FILEIO_TYPES_HEADER +#define FILEIO_TYPES_HEADER + +#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_compressionParameters */ +#include "../lib/zstd.h" /* ZSTD_* */ + +/*-************************************* +* Parameters: FIO_prefs_t +***************************************/ + +typedef struct FIO_display_prefs_s FIO_display_prefs_t; + +typedef enum { FIO_ps_auto, FIO_ps_never, FIO_ps_always } FIO_progressSetting_e; + +struct FIO_display_prefs_s { + int displayLevel; /* 0 : no display; 1: errors; 2: + result + interaction + warnings; 3: + progression; 4: + information */ + FIO_progressSetting_e progressSetting; +}; + + +typedef enum { FIO_zstdCompression, FIO_gzipCompression, FIO_xzCompression, FIO_lzmaCompression, FIO_lz4Compression } FIO_compressionType_t; + +typedef struct FIO_prefs_s { + + /* Algorithm preferences */ + FIO_compressionType_t compressionType; + U32 sparseFileSupport; /* 0: no sparse allowed; 1: auto (file yes, stdout no); 2: force sparse */ + int dictIDFlag; + int checksumFlag; + int blockSize; + int overlapLog; + U32 adaptiveMode; + U32 useRowMatchFinder; + int rsyncable; + int minAdaptLevel; + int maxAdaptLevel; + int ldmFlag; + int ldmHashLog; + int ldmMinMatch; + int ldmBucketSizeLog; + int ldmHashRateLog; + size_t streamSrcSize; + size_t targetCBlockSize; + int srcSizeHint; + int testMode; + ZSTD_paramSwitch_e literalCompressionMode; + + /* IO preferences */ + U32 removeSrcFile; + U32 overwrite; + U32 asyncIO; + + /* Computation resources preferences */ + unsigned memLimit; + int nbWorkers; + + int excludeCompressedFiles; + int patchFromMode; + int contentSize; + int allowBlockDevices; +} FIO_prefs_t; + +#endif /* FILEIO_TYPES_HEADER */ \ No newline at end of file From f16ed30946c659fa89ead4a6a3d84f05e1a01c10 Mon Sep 17 00:00:00 2001 From: Yonatan Komornik Date: Fri, 21 Jan 2022 14:49:51 -0800 Subject: [PATCH 02/23] Bugfix - rename fileio_asycio to fileio_asyncio --- programs/Makefile | 8 ++++---- programs/fileio.c | 2 +- programs/{fileio_asycio.c => fileio_asyncio.c} | 2 +- programs/{fileio_asycio.h => fileio_asyncio.h} | 0 4 files changed, 6 insertions(+), 6 deletions(-) rename programs/{fileio_asycio.c => fileio_asyncio.c} (99%) rename programs/{fileio_asycio.h => fileio_asyncio.h} (100%) diff --git a/programs/Makefile b/programs/Makefile index 82aa498950f..16763e49365 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -243,17 +243,17 @@ zstd-pgo : ## zstd-small: minimal target, supporting only zstd compression and decompression. no bench. no legacy. no other format. zstd-small: CFLAGS = -Os -s -zstd-frugal zstd-small: $(ZSTDLIB_CORE_SRC) zstdcli.c util.c timefn.c fileio.c fileio_asycio.c +zstd-frugal zstd-small: $(ZSTDLIB_CORE_SRC) zstdcli.c util.c timefn.c fileio.c fileio_asyncio.c $(CC) $(FLAGS) -DZSTD_NOBENCH -DZSTD_NODICT -DZSTD_NOTRACE -UZSTD_LEGACY_SUPPORT -DZSTD_LEGACY_SUPPORT=0 $^ -o $@$(EXT) -zstd-decompress: $(ZSTDLIB_COMMON_SRC) $(ZSTDLIB_DECOMPRESS_SRC) zstdcli.c util.c timefn.c fileio.c fileio_asycio.c +zstd-decompress: $(ZSTDLIB_COMMON_SRC) $(ZSTDLIB_DECOMPRESS_SRC) zstdcli.c util.c timefn.c fileio.c fileio_asyncio.c $(CC) $(FLAGS) -DZSTD_NOBENCH -DZSTD_NODICT -DZSTD_NOCOMPRESS -DZSTD_NOTRACE -UZSTD_LEGACY_SUPPORT -DZSTD_LEGACY_SUPPORT=0 $^ -o $@$(EXT) -zstd-compress: $(ZSTDLIB_COMMON_SRC) $(ZSTDLIB_COMPRESS_SRC) zstdcli.c util.c timefn.c fileio.c fileio_asycio.c +zstd-compress: $(ZSTDLIB_COMMON_SRC) $(ZSTDLIB_COMPRESS_SRC) zstdcli.c util.c timefn.c fileio.c fileio_asyncio.c $(CC) $(FLAGS) -DZSTD_NOBENCH -DZSTD_NODICT -DZSTD_NODECOMPRESS -DZSTD_NOTRACE -UZSTD_LEGACY_SUPPORT -DZSTD_LEGACY_SUPPORT=0 $^ -o $@$(EXT) ## zstd-dictBuilder: executable supporting dictionary creation and compression (only) -zstd-dictBuilder: $(ZSTDLIB_COMMON_SRC) $(ZSTDLIB_COMPRESS_SRC) $(ZDICT_SRC) zstdcli.c util.c timefn.c fileio.c fileio_asycio.c dibio.c +zstd-dictBuilder: $(ZSTDLIB_COMMON_SRC) $(ZSTDLIB_COMPRESS_SRC) $(ZDICT_SRC) zstdcli.c util.c timefn.c fileio.c fileio_asyncio.c dibio.c $(CC) $(FLAGS) -DZSTD_NOBENCH -DZSTD_NODECOMPRESS -DZSTD_NOTRACE $^ -o $@$(EXT) zstdmt: zstd diff --git a/programs/fileio.c b/programs/fileio.c index 383c3dd107f..2b0639a86ab 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -41,7 +41,7 @@ #endif #include "fileio.h" -#include "fileio_asycio.h" +#include "fileio_asyncio.h" #include "fileio_common.h" FIO_display_prefs_t g_display_prefs = {2, FIO_ps_auto}; diff --git a/programs/fileio_asycio.c b/programs/fileio_asyncio.c similarity index 99% rename from programs/fileio_asycio.c rename to programs/fileio_asyncio.c index 4bb2808b75f..9b4bf07a59c 100644 --- a/programs/fileio_asycio.c +++ b/programs/fileio_asyncio.c @@ -9,7 +9,7 @@ # include #endif -#include "fileio_asycio.h" +#include "fileio_asyncio.h" #include "fileio_common.h" /* ********************************************************************** diff --git a/programs/fileio_asycio.h b/programs/fileio_asyncio.h similarity index 100% rename from programs/fileio_asycio.h rename to programs/fileio_asyncio.h From d95ef84b0892b8ea56c629f04a9462f23545a09f Mon Sep 17 00:00:00 2001 From: Yonatan Komornik Date: Fri, 21 Jan 2022 16:35:50 -0800 Subject: [PATCH 03/23] Added copyrights & license to new files --- programs/fileio_asyncio.c | 10 ++++++++++ programs/fileio_asyncio.h | 10 ++++++++++ programs/fileio_common.h | 10 ++++++++++ programs/fileio_types.h | 10 ++++++++++ 4 files changed, 40 insertions(+) diff --git a/programs/fileio_asyncio.c b/programs/fileio_asyncio.c index 9b4bf07a59c..a174b41e5f1 100644 --- a/programs/fileio_asyncio.c +++ b/programs/fileio_asyncio.c @@ -1,3 +1,13 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + #include "platform.h" #include /* fprintf, open, fdopen, fread, _fileno, stdin, stdout */ #include /* malloc, free */ diff --git a/programs/fileio_asyncio.h b/programs/fileio_asyncio.h index 65cee434442..4b3b58a0788 100644 --- a/programs/fileio_asyncio.h +++ b/programs/fileio_asyncio.h @@ -1,3 +1,13 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + #ifndef ZSTD_FILEIO_ASYNCIO_H #define ZSTD_FILEIO_ASYNCIO_H diff --git a/programs/fileio_common.h b/programs/fileio_common.h index d5bb1d0c19b..d33c19d7bd1 100644 --- a/programs/fileio_common.h +++ b/programs/fileio_common.h @@ -1,3 +1,13 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + #ifndef ZSTD_FILEIO_COMMON_H #define ZSTD_FILEIO_COMMON_H diff --git a/programs/fileio_types.h b/programs/fileio_types.h index 80f55394fad..1909ab1ab5a 100644 --- a/programs/fileio_types.h +++ b/programs/fileio_types.h @@ -1,3 +1,13 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + #ifndef FILEIO_TYPES_HEADER #define FILEIO_TYPES_HEADER From 6a36ac7d9a8a5afacd592598341d7c310e5f0b87 Mon Sep 17 00:00:00 2001 From: Yonatan Komornik Date: Mon, 24 Jan 2022 13:53:45 -0800 Subject: [PATCH 04/23] CR fixes --- programs/fileio.c | 62 ++++++++-------- programs/fileio_asyncio.c | 144 +++++++++++++++++++------------------- programs/fileio_asyncio.h | 52 +++++++------- 3 files changed, 129 insertions(+), 129 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index 2b0639a86ab..d868883922b 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -1888,7 +1888,7 @@ typedef struct { size_t srcBufferSize; size_t srcBufferLoaded; ZSTD_DStream* dctx; - write_pool_ctx_t *writeCtx; + WritePoolCtx_t *writeCtx; } dRess_t; static dRess_t FIO_createDResources(FIO_prefs_t* const prefs, const char* dictFileName) @@ -1918,7 +1918,7 @@ static dRess_t FIO_createDResources(FIO_prefs_t* const prefs, const char* dictFi free(dictBuffer); } - ress.writeCtx = WritePool_create(prefs, ZSTD_DStreamOutSize()); + ress.writeCtx = AIO_WritePool_create(prefs, ZSTD_DStreamOutSize()); return ress; } @@ -1927,7 +1927,7 @@ static void FIO_freeDResources(dRess_t ress) { CHECK( ZSTD_freeDStream(ress.dctx) ); free(ress.srcBuffer); - WritePool_free(ress.writeCtx); + AIO_WritePool_free(ress.writeCtx); } /* FIO_consumeDSrcBuffer: @@ -1958,7 +1958,7 @@ static int FIO_passThrough(const FIO_prefs_t* const prefs, do { readFromInput = fread(buffer, 1, blockSize, finput); - storedSkips = FIO_fwriteSparse(foutput, buffer, readFromInput, prefs, storedSkips); + storedSkips = AIO_fwriteSparse(foutput, buffer, readFromInput, prefs, storedSkips); } while (readFromInput == blockSize); if (ferror(finput)) { DISPLAYLEVEL(1, "Pass-through read error : %s\n", strerror(errno)); @@ -1966,7 +1966,7 @@ static int FIO_passThrough(const FIO_prefs_t* const prefs, } assert(feof(finput)); - FIO_fwriteSparseEnd(prefs, foutput, storedSkips); + AIO_fwriteSparseEnd(prefs, foutput, storedSkips); return 0; } @@ -2013,7 +2013,7 @@ FIO_decompressZstdFrame(FIO_ctx_t* const fCtx, dRess_t* ress, FILE* finput, U64 alreadyDecoded) /* for multi-frames streams */ { U64 frameSize = 0; - io_job_t *writeJob = WritePool_acquireJob(ress->writeCtx); + IOJob_t *writeJob = AIO_WritePool_acquireJob(ress->writeCtx); /* display last 20 characters only */ { size_t const srcFileLength = strlen(srcFileName); @@ -2041,13 +2041,13 @@ FIO_decompressZstdFrame(FIO_ctx_t* const fCtx, dRess_t* ress, FILE* finput, DISPLAYLEVEL(1, "%s : Decoding error (36) : %s \n", srcFileName, ZSTD_getErrorName(readSizeHint)); FIO_zstdErrorHelp(prefs, ress, readSizeHint, srcFileName); - WritePool_releaseIoJob(writeJob); + AIO_WritePool_releaseIoJob(writeJob); return FIO_ERROR_FRAME_DECODING; } /* Write block */ writeJob->usedBufferSize = outBuff.pos; - WritePool_enqueueAndReacquireWriteJob(&writeJob); + AIO_WritePool_enqueueAndReacquireWriteJob(&writeJob); frameSize += outBuff.pos; if (fCtx->nbFilesTotal > 1) { size_t srcFileNameSize = strlen(srcFileName); @@ -2082,8 +2082,8 @@ FIO_decompressZstdFrame(FIO_ctx_t* const fCtx, dRess_t* ress, FILE* finput, ress->srcBufferLoaded += readSize; } } } - WritePool_releaseIoJob(writeJob); - WritePool_sparseWriteEnd(ress->writeCtx); + AIO_WritePool_releaseIoJob(writeJob); + AIO_WritePool_sparseWriteEnd(ress->writeCtx); return frameSize; } @@ -2097,7 +2097,7 @@ FIO_decompressGzFrame(dRess_t* ress, FILE* srcFile, const char* srcFileName) z_stream strm; int flush = Z_NO_FLUSH; int decodingError = 0; - io_job_t *writeJob = NULL; + IOJob_t *writeJob = NULL; strm.zalloc = Z_NULL; strm.zfree = Z_NULL; @@ -2108,7 +2108,7 @@ FIO_decompressGzFrame(dRess_t* ress, FILE* srcFile, const char* srcFileName) if (inflateInit2(&strm, 15 /* maxWindowLogSize */ + 16 /* gzip only */) != Z_OK) return FIO_ERROR_FRAME_DECODING; - writeJob = WritePool_acquireJob(ress->writeCtx); + writeJob = AIO_WritePool_acquireJob(ress->writeCtx); strm.next_out = (Bytef*)writeJob->buffer; strm.avail_out = (uInt)writeJob->bufferSize; strm.avail_in = (uInt)ress->srcBufferLoaded; @@ -2134,7 +2134,7 @@ FIO_decompressGzFrame(dRess_t* ress, FILE* srcFile, const char* srcFileName) { size_t const decompBytes = writeJob->bufferSize - strm.avail_out; if (decompBytes) { writeJob->usedBufferSize = decompBytes; - WritePool_enqueueAndReacquireWriteJob(&writeJob); + AIO_WritePool_enqueueAndReacquireWriteJob(&writeJob); outFileSize += decompBytes; strm.next_out = (Bytef*)writeJob->buffer; strm.avail_out = (uInt)writeJob->bufferSize; @@ -2150,8 +2150,8 @@ FIO_decompressGzFrame(dRess_t* ress, FILE* srcFile, const char* srcFileName) DISPLAYLEVEL(1, "zstd: %s: inflateEnd error \n", srcFileName); decodingError = 1; } - WritePool_releaseIoJob(writeJob); - WritePool_sparseWriteEnd(ress->writeCtx); + AIO_WritePool_releaseIoJob(writeJob); + AIO_WritePool_sparseWriteEnd(ress->writeCtx); return decodingError ? FIO_ERROR_FRAME_DECODING : outFileSize; } #endif @@ -2166,7 +2166,7 @@ FIO_decompressLzmaFrame(dRess_t* ress, FILE* srcFile, lzma_action action = LZMA_RUN; lzma_ret initRet; int decodingError = 0; - io_job_t *writeJob = NULL; + IOJob_t *writeJob = NULL; strm.next_in = 0; strm.avail_in = 0; @@ -2183,7 +2183,7 @@ FIO_decompressLzmaFrame(dRess_t* ress, FILE* srcFile, return FIO_ERROR_FRAME_DECODING; } - writeJob = WritePool_acquireJob(ress->writeCtx); + writeJob = AIO_WritePool_acquireJob(ress->writeCtx); strm.next_out = (Bytef*)writeJob->buffer; strm.avail_out = (uInt)writeJob->bufferSize; strm.next_in = (BYTE const*)ress->srcBuffer; @@ -2211,7 +2211,7 @@ FIO_decompressLzmaFrame(dRess_t* ress, FILE* srcFile, { size_t const decompBytes = writeJob->bufferSize - strm.avail_out; if (decompBytes) { writeJob->usedBufferSize = decompBytes; - WritePool_enqueueAndReacquireWriteJob(&writeJob); + AIO_WritePool_enqueueAndReacquireWriteJob(&writeJob); outFileSize += decompBytes; strm.next_out = (Bytef*)writeJob->buffer; strm.avail_out = writeJob->bufferSize; @@ -2221,8 +2221,8 @@ FIO_decompressLzmaFrame(dRess_t* ress, FILE* srcFile, FIO_consumeDSrcBuffer(ress, ress->srcBufferLoaded - strm.avail_in); lzma_end(&strm); - WritePool_releaseIoJob(writeJob); - WritePool_sparseWriteEnd(ress->writeCtx); + AIO_WritePool_releaseIoJob(writeJob); + AIO_WritePool_sparseWriteEnd(ress->writeCtx); return decodingError ? FIO_ERROR_FRAME_DECODING : outFileSize; } #endif @@ -2237,14 +2237,14 @@ FIO_decompressLz4Frame(dRess_t* ress, FILE* srcFile, LZ4F_decompressionContext_t dCtx; LZ4F_errorCode_t const errorCode = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION); int decodingError = 0; - io_job_t *writeJob = NULL; + IOJob_t *writeJob = NULL; if (LZ4F_isError(errorCode)) { DISPLAYLEVEL(1, "zstd: failed to create lz4 decompression context \n"); return FIO_ERROR_FRAME_DECODING; } - writeJob = WritePool_acquireJob(ress->writeCtx); + writeJob = AIO_WritePool_acquireJob(ress->writeCtx); /* Main Loop */ for (;nextToLoad;) { @@ -2282,7 +2282,7 @@ FIO_decompressLz4Frame(dRess_t* ress, FILE* srcFile, if (decodedBytes) { UTIL_HumanReadableSize_t hrs; writeJob->usedBufferSize = decodedBytes; - WritePool_enqueueAndReacquireWriteJob(&writeJob); + AIO_WritePool_enqueueAndReacquireWriteJob(&writeJob); filesize += decodedBytes; hrs = UTIL_makeHumanReadableSize(filesize); DISPLAYUPDATE(2, "\rDecompressed : %.*f%s ", hrs.precision, hrs.value, hrs.suffix); @@ -2298,8 +2298,8 @@ FIO_decompressLz4Frame(dRess_t* ress, FILE* srcFile, } LZ4F_freeDecompressionContext(dCtx); - WritePool_releaseIoJob(writeJob); - WritePool_sparseWriteEnd(ress->writeCtx); + AIO_WritePool_releaseIoJob(writeJob); + AIO_WritePool_sparseWriteEnd(ress->writeCtx); return decodingError ? FIO_ERROR_FRAME_DECODING : filesize; } @@ -2376,7 +2376,7 @@ static int FIO_decompressFrames(FIO_ctx_t* const fCtx, #endif } else if ((prefs->overwrite) && !strcmp (dstFileName, stdoutmark)) { /* pass-through mode */ return FIO_passThrough(prefs, - WritePool_getFile(ress.writeCtx), srcFile, + AIO_WritePool_getFile(ress.writeCtx), srcFile, ress.srcBuffer, ress.srcBufferSize, ress.srcBufferLoaded); } else { @@ -2414,7 +2414,7 @@ static int FIO_decompressDstFile(FIO_ctx_t* const fCtx, int releaseDstFile = 0; int transferMTime = 0; - if ((WritePool_getFile(ress.writeCtx) == NULL) && (prefs->testMode == 0)) { + if ((AIO_WritePool_getFile(ress.writeCtx) == NULL) && (prefs->testMode == 0)) { FILE *dstFile; int dstFilePermissions = DEFAULT_FILE_PERMISSIONS; if ( strcmp(srcFileName, stdinmark) /* special case : don't transfer permissions from stdin */ @@ -2429,7 +2429,7 @@ static int FIO_decompressDstFile(FIO_ctx_t* const fCtx, dstFile = FIO_openDstFile(fCtx, prefs, srcFileName, dstFileName, dstFilePermissions); if (dstFile==NULL) return 1; - WritePool_setFile(ress.writeCtx, dstFile); + AIO_WritePool_setFile(ress.writeCtx, dstFile); /* Must only be added after FIO_openDstFile() succeeds. * Otherwise we may delete the destination file if it already exists, @@ -2442,7 +2442,7 @@ static int FIO_decompressDstFile(FIO_ctx_t* const fCtx, if (releaseDstFile) { clearHandler(); - if (WritePool_closeFile(ress.writeCtx)) { + if (AIO_WritePool_closeFile(ress.writeCtx)) { DISPLAYLEVEL(1, "zstd: %s: %s \n", dstFileName, strerror(errno)); result = 1; } @@ -2658,14 +2658,14 @@ FIO_decompressMultipleFilenames(FIO_ctx_t* const fCtx, if (!prefs->testMode) { FILE* dstFile = FIO_openDstFile(fCtx, prefs, NULL, outFileName, DEFAULT_FILE_PERMISSIONS); if (dstFile == 0) EXM_THROW(19, "cannot open %s", outFileName); - WritePool_setFile(ress.writeCtx, dstFile); + AIO_WritePool_setFile(ress.writeCtx, dstFile); } for (; fCtx->currFileIdx < fCtx->nbFilesTotal; fCtx->currFileIdx++) { status = FIO_decompressSrcFile(fCtx, prefs, ress, outFileName, srcNamesTable[fCtx->currFileIdx]); if (!status) fCtx->nbFilesProcessed++; error |= status; } - if ((!prefs->testMode) && (WritePool_closeFile(ress.writeCtx))) + if ((!prefs->testMode) && (AIO_WritePool_closeFile(ress.writeCtx))) EXM_THROW(72, "Write error : %s : cannot properly close output file", strerror(errno)); } else { diff --git a/programs/fileio_asyncio.c b/programs/fileio_asyncio.c index a174b41e5f1..868720a1da2 100644 --- a/programs/fileio_asyncio.c +++ b/programs/fileio_asyncio.c @@ -26,10 +26,10 @@ * Sparse write ************************************************************************/ -/** FIO_fwriteSparse() : +/** AIO_fwriteSparse() : * @return : storedSkips, -* argument for next call to FIO_fwriteSparse() or FIO_fwriteSparseEnd() */ -unsigned FIO_fwriteSparse(FILE* file, +* argument for next call to AIO_fwriteSparse() or AIO_fwriteSparseEnd() */ +unsigned AIO_fwriteSparse(FILE* file, const void* buffer, size_t bufferSize, const FIO_prefs_t* const prefs, unsigned storedSkips) @@ -106,7 +106,7 @@ unsigned FIO_fwriteSparse(FILE* file, return storedSkips; } -void FIO_fwriteSparseEnd(const FIO_prefs_t* const prefs, FILE* file, unsigned storedSkips) +void AIO_fwriteSparseEnd(const FIO_prefs_t* const prefs, FILE* file, unsigned storedSkips) { if (prefs->testMode) assert(storedSkips == 0); if (storedSkips>0) { @@ -131,10 +131,10 @@ void FIO_fwriteSparseEnd(const FIO_prefs_t* const prefs, FILE* file, unsigned st * General IoPool implementation *************************************/ -static io_job_t *IoPool_createIoJob(io_pool_ctx_t *ctx, size_t bufferSize) { +static IOJob_t *AIO_IOPool_createIoJob(IOPoolCtx_t *ctx, size_t bufferSize) { void *buffer; - io_job_t *job; - job = (io_job_t*) malloc(sizeof(io_job_t)); + IOJob_t *job; + job = (IOJob_t*) malloc(sizeof(IOJob_t)); buffer = malloc(bufferSize); if(!job || !buffer) EXM_THROW(101, "Allocation error : not enough memory"); @@ -148,10 +148,10 @@ static io_job_t *IoPool_createIoJob(io_pool_ctx_t *ctx, size_t bufferSize) { } -/* IoPool_createThreadPool: +/* AIO_IOPool_createThreadPool: * Creates a thread pool and a mutex for threaded IO pool. * Displays warning if asyncio is requested but MT isn't available. */ -static void IoPool_createThreadPool(io_pool_ctx_t *ctx, const FIO_prefs_t *prefs) { +static void AIO_IOPool_createThreadPool(IOPoolCtx_t *ctx, const FIO_prefs_t *prefs) { ctx->threadPool = NULL; if(prefs->asyncIO) { if (ZSTD_pthread_mutex_init(&ctx->ioJobsMutex, NULL)) @@ -165,26 +165,26 @@ static void IoPool_createThreadPool(io_pool_ctx_t *ctx, const FIO_prefs_t *prefs } } -/* IoPool_init: +/* AIO_IOPool_init: * Allocates and sets and a new write pool including its included availableJobs. */ -static void IoPool_init(io_pool_ctx_t *ctx, FIO_prefs_t* const prefs, POOL_function poolFunction, size_t bufferSize) { +static void AIO_IOPool_init(IOPoolCtx_t *ctx, FIO_prefs_t* const prefs, POOL_function poolFunction, size_t bufferSize) { int i; - IoPool_createThreadPool(ctx, prefs); + AIO_IOPool_createThreadPool(ctx, prefs); ctx->prefs = prefs; ctx->poolFunction = poolFunction; ctx->totalIoJobs = ctx->threadPool ? MAX_IO_JOBS : 1; ctx->availableJobsCount = ctx->totalIoJobs; for(i=0; i < ctx->availableJobsCount; i++) { - ctx->availableJobs[i] = IoPool_createIoJob(ctx, bufferSize); + ctx->availableJobs[i] = AIO_IOPool_createIoJob(ctx, bufferSize); } ctx->file = NULL; } -/* IoPool_releaseIoJob: +/* AIO_IOPool_releaseIoJob: * Releases an acquired job back to the pool. Doesn't execute the job. */ -static void IoPool_releaseIoJob(io_job_t *job) { - io_pool_ctx_t *ctx = (io_pool_ctx_t *) job->ctx; +static void AIO_IOPool_releaseIoJob(IOJob_t *job) { + IOPoolCtx_t *ctx = (IOPoolCtx_t *) job->ctx; if(ctx->threadPool) { ZSTD_pthread_mutex_lock(&ctx->ioJobsMutex); assert(ctx->availableJobsCount < MAX_IO_JOBS); @@ -196,20 +196,20 @@ static void IoPool_releaseIoJob(io_job_t *job) { } } -/* IoPool_join: +/* AIO_IOPool_join: * Waits for all tasks in the pool to finish executing. */ -static void IoPool_join(io_pool_ctx_t* ctx) { +static void AIO_IOPool_join(IOPoolCtx_t* ctx) { if(ctx->threadPool) POOL_joinJobs(ctx->threadPool); } -/* IoPool_free: +/* AIO_IOPool_free: * Release a previously allocated write thread pool. Makes sure all takss are done and released. */ -static void IoPool_destroy(io_pool_ctx_t* ctx) { +static void AIO_IOPool_destroy(IOPoolCtx_t* ctx) { int i; if(ctx->threadPool) { /* Make sure we finish all tasks and then free the resources */ - IoPool_join(ctx); + AIO_IOPool_join(ctx); /* Make sure we are not leaking availableJobs */ assert(ctx->availableJobsCount == ctx->totalIoJobs); POOL_free(ctx->threadPool); @@ -217,26 +217,26 @@ static void IoPool_destroy(io_pool_ctx_t* ctx) { } assert(ctx->file == NULL); for(i=0; iavailableJobsCount; i++) { - io_job_t* job = (io_job_t*) ctx->availableJobs[i]; + IOJob_t* job = (IOJob_t*) ctx->availableJobs[i]; free(job->buffer); free(job); } } -/* IoPool_acquireJob: +/* AIO_IOPool_acquireJob: * Returns an available io job to be used for a future io. */ -static io_job_t* IoPool_acquireJob(io_pool_ctx_t *ctx) { - io_job_t *job; +static IOJob_t* AIO_IOPool_acquireJob(IOPoolCtx_t *ctx) { + IOJob_t *job; assert(ctx->file != NULL || ctx->prefs->testMode); if(ctx->threadPool) { ZSTD_pthread_mutex_lock(&ctx->ioJobsMutex); assert(ctx->availableJobsCount > 0); - job = (io_job_t*) ctx->availableJobs[--ctx->availableJobsCount]; + job = (IOJob_t*) ctx->availableJobs[--ctx->availableJobsCount]; ZSTD_pthread_mutex_unlock(&ctx->ioJobsMutex); } else { assert(ctx->availableJobsCount == 1); ctx->availableJobsCount--; - job = (io_job_t*)ctx->availableJobs[0]; + job = (IOJob_t*)ctx->availableJobs[0]; } job->usedBufferSize = 0; job->file = ctx->file; @@ -245,26 +245,26 @@ static io_job_t* IoPool_acquireJob(io_pool_ctx_t *ctx) { } -/* IoPool_setFile: +/* AIO_IOPool_setFile: * Sets the destination file for future files in the pool. * Requires completion of all queues write jobs and release of all otherwise acquired jobs. * Also requires ending of sparse write if a previous file was used in sparse mode. */ -static void IoPool_setFile(io_pool_ctx_t *ctx, FILE* file) { +static void AIO_IOPool_setFile(IOPoolCtx_t *ctx, FILE* file) { assert(ctx!=NULL); - IoPool_join(ctx); + AIO_IOPool_join(ctx); assert(ctx->availableJobsCount == ctx->totalIoJobs); ctx->file = file; } -static FILE* IoPool_getFile(io_pool_ctx_t *ctx) { +static FILE* AIO_IOPool_getFile(IOPoolCtx_t *ctx) { return ctx->file; } -/* IoPool_enqueueJob: +/* AIO_IOPool_enqueueJob: * Enqueues an io job for execution. * The queued job shouldn't be used directly after queueing it. */ -static void IoPool_enqueueJob(io_job_t *job) { - io_pool_ctx_t* ctx = (io_pool_ctx_t *)job->ctx; +static void AIO_IOPool_enqueueJob(IOJob_t *job) { + IOPoolCtx_t* ctx = (IOPoolCtx_t *)job->ctx; if(ctx->threadPool) POOL_add(ctx->threadPool, ctx->poolFunction, job); else @@ -275,91 +275,91 @@ static void IoPool_enqueueJob(io_job_t *job) { * WritePool implementation *************************************/ -/* WritePool_acquireJob: +/* AIO_WritePool_acquireJob: * Returns an available write job to be used for a future write. */ -io_job_t* WritePool_acquireJob(write_pool_ctx_t *ctx) { - return IoPool_acquireJob(&ctx->base); +IOJob_t* AIO_WritePool_acquireJob(WritePoolCtx_t *ctx) { + return AIO_IOPool_acquireJob(&ctx->base); } -/* WritePool_enqueueAndReacquireWriteJob: +/* AIO_WritePool_enqueueAndReacquireWriteJob: * Queues a write job for execution and acquires a new one. * After execution `job`'s pointed value would change to the newly acquired job. * Make sure to set `usedBufferSize` to the wanted length before call. * The queued job shouldn't be used directly after queueing it. */ -void WritePool_enqueueAndReacquireWriteJob(io_job_t **job) { - IoPool_enqueueJob(*job); - *job = IoPool_acquireJob((io_pool_ctx_t *)(*job)->ctx); +void AIO_WritePool_enqueueAndReacquireWriteJob(IOJob_t **job) { + AIO_IOPool_enqueueJob(*job); + *job = AIO_IOPool_acquireJob((IOPoolCtx_t *)(*job)->ctx); } -/* WritePool_sparseWriteEnd: +/* AIO_WritePool_sparseWriteEnd: * Ends sparse writes to the current file. * Blocks on completion of all current write jobs before executing. */ -void WritePool_sparseWriteEnd(write_pool_ctx_t *ctx) { +void AIO_WritePool_sparseWriteEnd(WritePoolCtx_t *ctx) { assert(ctx != NULL); if(ctx->base.threadPool) POOL_joinJobs(ctx->base.threadPool); - FIO_fwriteSparseEnd(ctx->base.prefs, ctx->base.file, ctx->storedSkips); + AIO_fwriteSparseEnd(ctx->base.prefs, ctx->base.file, ctx->storedSkips); ctx->storedSkips = 0; } -/* WritePool_setFile: +/* AIO_WritePool_setFile: * Sets the destination file for future writes in the pool. * Requires completion of all queues write jobs and release of all otherwise acquired jobs. * Also requires ending of sparse write if a previous file was used in sparse mode. */ -void WritePool_setFile(write_pool_ctx_t *ctx, FILE* file) { - IoPool_setFile(&ctx->base, file); +void AIO_WritePool_setFile(WritePoolCtx_t *ctx, FILE* file) { + AIO_IOPool_setFile(&ctx->base, file); assert(ctx->storedSkips == 0); } -/* WritePool_getFile: +/* AIO_WritePool_getFile: * Returns the file the writePool is currently set to write to. */ -FILE* WritePool_getFile(write_pool_ctx_t *ctx) { - return IoPool_getFile(&ctx->base); +FILE* AIO_WritePool_getFile(WritePoolCtx_t *ctx) { + return AIO_IOPool_getFile(&ctx->base); } -/* WritePool_releaseIoJob: +/* AIO_WritePool_releaseIoJob: * Releases an acquired job back to the pool. Doesn't execute the job. */ -void WritePool_releaseIoJob(io_job_t *job) { - IoPool_releaseIoJob(job); +void AIO_WritePool_releaseIoJob(IOJob_t *job) { + AIO_IOPool_releaseIoJob(job); } -/* WritePool_closeFile: +/* AIO_WritePool_closeFile: * Ends sparse write and closes the writePool's current file and sets the file to NULL. * Requires completion of all queues write jobs and release of all otherwise acquired jobs. */ -int WritePool_closeFile(write_pool_ctx_t *ctx) { +int AIO_WritePool_closeFile(WritePoolCtx_t *ctx) { FILE *dstFile = ctx->base.file; assert(dstFile!=NULL || ctx->base.prefs->testMode!=0); - WritePool_sparseWriteEnd(ctx); - IoPool_setFile(&ctx->base, NULL); + AIO_WritePool_sparseWriteEnd(ctx); + AIO_IOPool_setFile(&ctx->base, NULL); return fclose(dstFile); } -/* WritePool_executeWriteJob: +/* AIO_WritePool_executeWriteJob: * Executes a write job synchronously. Can be used as a function for a thread pool. */ -static void WritePool_executeWriteJob(void* opaque){ - io_job_t* job = (io_job_t*) opaque; - write_pool_ctx_t* ctx = (write_pool_ctx_t*) job->ctx; - ctx->storedSkips = FIO_fwriteSparse(job->file, job->buffer, job->usedBufferSize, ctx->base.prefs, ctx->storedSkips); - IoPool_releaseIoJob(job); +static void AIO_WritePool_executeWriteJob(void* opaque){ + IOJob_t* job = (IOJob_t*) opaque; + WritePoolCtx_t* ctx = (WritePoolCtx_t*) job->ctx; + ctx->storedSkips = AIO_fwriteSparse(job->file, job->buffer, job->usedBufferSize, ctx->base.prefs, ctx->storedSkips); + AIO_IOPool_releaseIoJob(job); } -/* WritePool_create: +/* AIO_WritePool_create: * Allocates and sets and a new write pool including its included jobs. */ -write_pool_ctx_t* WritePool_create(FIO_prefs_t* const prefs, size_t bufferSize) { - write_pool_ctx_t* ctx = (write_pool_ctx_t*) malloc(sizeof(write_pool_ctx_t)); +WritePoolCtx_t* AIO_WritePool_create(FIO_prefs_t* const prefs, size_t bufferSize) { + WritePoolCtx_t* ctx = (WritePoolCtx_t*) malloc(sizeof(WritePoolCtx_t)); if(!ctx) EXM_THROW(100, "Allocation error : not enough memory"); - IoPool_init(&ctx->base, prefs, WritePool_executeWriteJob, bufferSize); + AIO_IOPool_init(&ctx->base, prefs, AIO_WritePool_executeWriteJob, bufferSize); ctx->storedSkips = 0; return ctx; } -/* WritePool_free: +/* AIO_WritePool_free: * Frees and releases a writePool and its resources. Closes destination file if needs to. */ -void WritePool_free(write_pool_ctx_t* ctx) { +void AIO_WritePool_free(WritePoolCtx_t* ctx) { /* Make sure we finish all tasks and then free the resources */ - if(WritePool_getFile(ctx)) - WritePool_closeFile(ctx); - IoPool_destroy(&ctx->base); + if(AIO_WritePool_getFile(ctx)) + AIO_WritePool_closeFile(ctx); + AIO_IOPool_destroy(&ctx->base); assert(ctx->storedSkips==0); free(ctx); } diff --git a/programs/fileio_asyncio.h b/programs/fileio_asyncio.h index 4b3b58a0788..3e91164c558 100644 --- a/programs/fileio_asyncio.h +++ b/programs/fileio_asyncio.h @@ -39,12 +39,12 @@ typedef struct { ZSTD_pthread_mutex_t ioJobsMutex; void* availableJobs[MAX_IO_JOBS]; int availableJobsCount; -} io_pool_ctx_t; +} IOPoolCtx_t; typedef struct { - io_pool_ctx_t base; + IOPoolCtx_t base; unsigned storedSkips; -} write_pool_ctx_t; +} WritePoolCtx_t; typedef struct { /* These fields are automatically set and shouldn't be changed by non WritePool code. */ @@ -57,61 +57,61 @@ typedef struct { * of bytes to write from the buffer. */ size_t usedBufferSize; U64 offset; -} io_job_t; +} IOJob_t; -/** FIO_fwriteSparse() : +/** AIO_fwriteSparse() : * @return : storedSkips, -* argument for next call to FIO_fwriteSparse() or FIO_fwriteSparseEnd() */ -unsigned FIO_fwriteSparse(FILE* file, +* argument for next call to AIO_fwriteSparse() or AIO_fwriteSparseEnd() */ +unsigned AIO_fwriteSparse(FILE* file, const void* buffer, size_t bufferSize, const FIO_prefs_t* const prefs, unsigned storedSkips); -void FIO_fwriteSparseEnd(const FIO_prefs_t* const prefs, FILE* file, unsigned storedSkips); +void AIO_fwriteSparseEnd(const FIO_prefs_t* const prefs, FILE* file, unsigned storedSkips); -/* WritePool_releaseIoJob: +/* AIO_WritePool_releaseIoJob: * Releases an acquired job back to the pool. Doesn't execute the job. */ -void WritePool_releaseIoJob(io_job_t *job); +void AIO_WritePool_releaseIoJob(IOJob_t *job); -/* WritePool_acquireJob: +/* AIO_WritePool_acquireJob: * Returns an available write job to be used for a future write. */ -io_job_t* WritePool_acquireJob(write_pool_ctx_t *ctx); +IOJob_t* AIO_WritePool_acquireJob(WritePoolCtx_t *ctx); -/* WritePool_enqueueAndReacquireWriteJob: +/* AIO_WritePool_enqueueAndReacquireWriteJob: * Enqueues a write job for execution and acquires a new one. * After execution `job`'s pointed value would change to the newly acquired job. * Make sure to set `usedBufferSize` to the wanted length before call. * The queued job shouldn't be used directly after queueing it. */ -void WritePool_enqueueAndReacquireWriteJob(io_job_t **job); +void AIO_WritePool_enqueueAndReacquireWriteJob(IOJob_t **job); -/* WritePool_sparseWriteEnd: +/* AIO_WritePool_sparseWriteEnd: * Ends sparse writes to the current file. * Blocks on completion of all current write jobs before executing. */ -void WritePool_sparseWriteEnd(write_pool_ctx_t *ctx); +void AIO_WritePool_sparseWriteEnd(WritePoolCtx_t *ctx); -/* WritePool_setFile: +/* AIO_WritePool_setFile: * Sets the destination file for future writes in the pool. * Requires completion of all queues write jobs and release of all otherwise acquired jobs. * Also requires ending of sparse write if a previous file was used in sparse mode. */ -void WritePool_setFile(write_pool_ctx_t *ctx, FILE* file); +void AIO_WritePool_setFile(WritePoolCtx_t *ctx, FILE* file); -/* WritePool_getFile: +/* AIO_WritePool_getFile: * Returns the file the writePool is currently set to write to. */ -FILE* WritePool_getFile(write_pool_ctx_t *ctx); +FILE* AIO_WritePool_getFile(WritePoolCtx_t *ctx); -/* WritePool_closeFile: +/* AIO_WritePool_closeFile: * Ends sparse write and closes the writePool's current file and sets the file to NULL. * Requires completion of all queues write jobs and release of all otherwise acquired jobs. */ -int WritePool_closeFile(write_pool_ctx_t *ctx); +int AIO_WritePool_closeFile(WritePoolCtx_t *ctx); -/* WritePool_create: +/* AIO_WritePool_create: * Allocates and sets and a new write pool including its included jobs. * bufferSize should be set to the maximal buffer we want to write to at a time. */ -write_pool_ctx_t* WritePool_create(FIO_prefs_t* const prefs, size_t bufferSize); +WritePoolCtx_t* AIO_WritePool_create(FIO_prefs_t* const prefs, size_t bufferSize); -/* WritePool_free: +/* AIO_WritePool_free: * Frees and releases a writePool and its resources. Closes destination file. */ -void WritePool_free(write_pool_ctx_t* ctx); +void AIO_WritePool_free(WritePoolCtx_t* ctx); #if defined (__cplusplus) } From 1bccf20d341e971cd0f5d84b8e4f117b0c4a01a4 Mon Sep 17 00:00:00 2001 From: Yonatan Komornik Date: Mon, 24 Jan 2022 14:08:32 -0800 Subject: [PATCH 05/23] Compression asyncio: - Added asyncio functionality for compression flow - Added ReadPool for async reads, embedded to both comp and decomp flows --- programs/fileio.c | 761 ++++++++++++++++++-------------------- programs/fileio_asyncio.c | 226 ++++++++++- programs/fileio_asyncio.h | 71 +++- programs/fileio_types.h | 2 +- tests/playTests.sh | 4 +- 5 files changed, 654 insertions(+), 410 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index d868883922b..4bf29d870a6 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -814,16 +814,12 @@ static int FIO_removeMultiFilesWarning(FIO_ctx_t* const fCtx, const FIO_prefs_t* * Compression ************************************************************************/ typedef struct { - FILE* srcFile; - FILE* dstFile; - void* srcBuffer; - size_t srcBufferSize; - void* dstBuffer; - size_t dstBufferSize; void* dictBuffer; size_t dictBufferSize; const char* dictFileName; ZSTD_CStream* cctx; + write_pool_ctx_t *writeCtx; + read_pool_ctx_t *readCtx; } cRess_t; /** ZSTD_cycleLog() : @@ -836,20 +832,20 @@ static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat) } static void FIO_adjustParamsForPatchFromMode(FIO_prefs_t* const prefs, - ZSTD_compressionParameters* comprParams, - unsigned long long const dictSize, - unsigned long long const maxSrcFileSize, - int cLevel) + ZSTD_compressionParameters* comprParams, + unsigned long long const dictSize, + unsigned long long const maxSrcFileSize, + int cLevel) { unsigned const fileWindowLog = FIO_highbit64(maxSrcFileSize) + 1; ZSTD_compressionParameters const cParams = ZSTD_getCParams(cLevel, (size_t)maxSrcFileSize, (size_t)dictSize); FIO_adjustMemLimitForPatchFromMode(prefs, dictSize, maxSrcFileSize); if (fileWindowLog > ZSTD_WINDOWLOG_MAX) - DISPLAYLEVEL(1, "Max window log exceeded by file (compression ratio will suffer)\n"); + DISPLAYLEVEL(1, "Max window log exceeded by file (compression ratio will suffer)\n"); comprParams->windowLog = MAX(ZSTD_WINDOWLOG_MIN, MIN(ZSTD_WINDOWLOG_MAX, fileWindowLog)); if (fileWindowLog > ZSTD_cycleLog(cParams.chainLog, cParams.strategy)) { if (!prefs->ldmFlag) - DISPLAYLEVEL(1, "long mode automatically triggered\n"); + DISPLAYLEVEL(1, "long mode automatically triggered\n"); FIO_setLdmFlag(prefs, 1); } if (cParams.strategy >= ZSTD_btopt) { @@ -870,11 +866,8 @@ static cRess_t FIO_createCResources(FIO_prefs_t* const prefs, DISPLAYLEVEL(6, "FIO_createCResources \n"); ress.cctx = ZSTD_createCCtx(); if (ress.cctx == NULL) - EXM_THROW(30, "allocation error (%s): can't create ZSTD_CCtx", - strerror(errno)); - ress.srcBufferSize = ZSTD_CStreamInSize(); - ress.srcBuffer = malloc(ress.srcBufferSize); - ress.dstBufferSize = ZSTD_CStreamOutSize(); + EXM_THROW(30, "allocation error (%s): can't create ZSTD_CCtx", + strerror(errno)); /* need to update memLimit before calling createDictBuffer * because of memLimit check inside it */ @@ -882,14 +875,14 @@ static cRess_t FIO_createCResources(FIO_prefs_t* const prefs, unsigned long long const ssSize = (unsigned long long)prefs->streamSrcSize; FIO_adjustParamsForPatchFromMode(prefs, &comprParams, UTIL_getFileSize(dictFileName), ssSize > 0 ? ssSize : maxSrcFileSize, cLevel); } - ress.dstBuffer = malloc(ress.dstBufferSize); ress.dictBufferSize = FIO_createDictBuffer(&ress.dictBuffer, dictFileName, prefs); /* works with dictFileName==NULL */ - if (!ress.srcBuffer || !ress.dstBuffer) - EXM_THROW(31, "allocation error : not enough memory"); + + ress.writeCtx = WritePool_create(prefs, ZSTD_CStreamOutSize()); + ress.readCtx = ReadPool_create(prefs, ZSTD_CStreamInSize()); /* Advanced parameters, including dictionary */ if (dictFileName && (ress.dictBuffer==NULL)) - EXM_THROW(32, "allocation error : can't create dictBuffer"); + EXM_THROW(32, "allocation error : can't create dictBuffer"); ress.dictFileName = dictFileName; if (prefs->adaptiveMode && !prefs->ldmFlag && !comprParams.windowLog) @@ -948,9 +941,9 @@ static cRess_t FIO_createCResources(FIO_prefs_t* const prefs, static void FIO_freeCResources(const cRess_t* const ress) { - free(ress->srcBuffer); - free(ress->dstBuffer); free(ress->dictBuffer); + WritePool_free(ress->writeCtx); + ReadPool_free(ress->readCtx); ZSTD_freeCStream(ress->cctx); /* never fails */ } @@ -963,6 +956,7 @@ FIO_compressGzFrame(const cRess_t* ress, /* buffers & handlers are used, but no { unsigned long long inFileSize = 0, outFileSize = 0; z_stream strm; + io_job_t *writeJob = NULL; if (compressionLevel > Z_BEST_COMPRESSION) compressionLevel = Z_BEST_COMPRESSION; @@ -972,67 +966,76 @@ FIO_compressGzFrame(const cRess_t* ress, /* buffers & handlers are used, but no strm.opaque = Z_NULL; { int const ret = deflateInit2(&strm, compressionLevel, Z_DEFLATED, - 15 /* maxWindowLogSize */ + 16 /* gzip only */, - 8, Z_DEFAULT_STRATEGY); /* see http://www.zlib.net/manual.html */ + 15 /* maxWindowLogSize */ + 16 /* gzip only */, + 8, Z_DEFAULT_STRATEGY); /* see http://www.zlib.net/manual.html */ if (ret != Z_OK) { EXM_THROW(71, "zstd: %s: deflateInit2 error %d \n", srcFileName, ret); - } } + } } + writeJob = WritePool_acquireJob(ress->writeCtx); strm.next_in = 0; strm.avail_in = 0; - strm.next_out = (Bytef*)ress->dstBuffer; - strm.avail_out = (uInt)ress->dstBufferSize; + strm.next_out = (Bytef*)writeJob->buffer; + strm.avail_out = (uInt)writeJob->bufferSize; while (1) { int ret; if (strm.avail_in == 0) { - size_t const inSize = fread(ress->srcBuffer, 1, ress->srcBufferSize, ress->srcFile); - if (inSize == 0) break; - inFileSize += inSize; - strm.next_in = (z_const unsigned char*)ress->srcBuffer; - strm.avail_in = (uInt)inSize; + ReadPool_fillBuffer(ress->readCtx, ZSTD_CStreamInSize()); + if (ress->readCtx->srcBufferLoaded == 0) break; + inFileSize += ress->readCtx->srcBufferLoaded; + strm.next_in = (z_const unsigned char*)ress->readCtx->srcBuffer; + strm.avail_in = (uInt)ress->readCtx->srcBufferLoaded; + } + + { + size_t const availBefore = strm.avail_in; + ret = deflate(&strm, Z_NO_FLUSH); + ReadPool_consumeBytes(ress->readCtx, availBefore - strm.avail_in); } - ret = deflate(&strm, Z_NO_FLUSH); + if (ret != Z_OK) - EXM_THROW(72, "zstd: %s: deflate error %d \n", srcFileName, ret); - { size_t const cSize = ress->dstBufferSize - strm.avail_out; + EXM_THROW(72, "zstd: %s: deflate error %d \n", srcFileName, ret); + { size_t const cSize = writeJob->bufferSize - strm.avail_out; if (cSize) { - if (fwrite(ress->dstBuffer, 1, cSize, ress->dstFile) != cSize) - EXM_THROW(73, "Write error : cannot write to output file : %s ", strerror(errno)); + writeJob->usedBufferSize = cSize; + WritePool_enqueueAndReacquireWriteJob(&writeJob); outFileSize += cSize; - strm.next_out = (Bytef*)ress->dstBuffer; - strm.avail_out = (uInt)ress->dstBufferSize; - } } + strm.next_out = (Bytef*)writeJob->buffer; + strm.avail_out = (uInt)writeJob->bufferSize; + } } if (srcFileSize == UTIL_FILESIZE_UNKNOWN) { DISPLAYUPDATE(2, "\rRead : %u MB ==> %.2f%% ", - (unsigned)(inFileSize>>20), - (double)outFileSize/inFileSize*100) + (unsigned)(inFileSize>>20), + (double)outFileSize/inFileSize*100) } else { DISPLAYUPDATE(2, "\rRead : %u / %u MB ==> %.2f%% ", - (unsigned)(inFileSize>>20), (unsigned)(srcFileSize>>20), - (double)outFileSize/inFileSize*100); - } } + (unsigned)(inFileSize>>20), (unsigned)(srcFileSize>>20), + (double)outFileSize/inFileSize*100); + } } while (1) { int const ret = deflate(&strm, Z_FINISH); - { size_t const cSize = ress->dstBufferSize - strm.avail_out; + { size_t const cSize = writeJob->bufferSize - strm.avail_out; if (cSize) { - if (fwrite(ress->dstBuffer, 1, cSize, ress->dstFile) != cSize) - EXM_THROW(75, "Write error : %s ", strerror(errno)); + writeJob->usedBufferSize = cSize; + WritePool_enqueueAndReacquireWriteJob(&writeJob); outFileSize += cSize; - strm.next_out = (Bytef*)ress->dstBuffer; - strm.avail_out = (uInt)ress->dstBufferSize; - } } + strm.next_out = (Bytef*)writeJob->buffer; + strm.avail_out = (uInt)writeJob->bufferSize; + } } if (ret == Z_STREAM_END) break; if (ret != Z_BUF_ERROR) - EXM_THROW(77, "zstd: %s: deflate error %d \n", srcFileName, ret); + EXM_THROW(77, "zstd: %s: deflate error %d \n", srcFileName, ret); } { int const ret = deflateEnd(&strm); if (ret != Z_OK) { EXM_THROW(79, "zstd: %s: deflateEnd error %d \n", srcFileName, ret); - } } + } } *readsize = inFileSize; + WritePool_releaseIoJob(writeJob); + WritePool_sparseWriteEnd(ress->writeCtx); return outFileSize; } #endif @@ -1048,6 +1051,7 @@ FIO_compressLzmaFrame(cRess_t* ress, lzma_stream strm = LZMA_STREAM_INIT; lzma_action action = LZMA_RUN; lzma_ret ret; + io_job_t *writeJob = NULL; if (compressionLevel < 0) compressionLevel = 0; if (compressionLevel > 9) compressionLevel = 9; @@ -1065,31 +1069,37 @@ FIO_compressLzmaFrame(cRess_t* ress, EXM_THROW(83, "zstd: %s: lzma_easy_encoder error %d", srcFileName, ret); } + writeJob = WritePool_acquireJob(ress->writeCtx); + strm.next_out = (Bytef*)writeJob->buffer; + strm.avail_out = (uInt)writeJob->bufferSize; strm.next_in = 0; strm.avail_in = 0; - strm.next_out = (BYTE*)ress->dstBuffer; - strm.avail_out = ress->dstBufferSize; while (1) { if (strm.avail_in == 0) { - size_t const inSize = fread(ress->srcBuffer, 1, ress->srcBufferSize, ress->srcFile); - if (inSize == 0) action = LZMA_FINISH; + size_t const inSize = ReadPool_fillBuffer(ress->readCtx, ZSTD_CStreamInSize()); + if (ress->readCtx->srcBufferLoaded == 0) action = LZMA_FINISH; inFileSize += inSize; - strm.next_in = (BYTE const*)ress->srcBuffer; - strm.avail_in = inSize; + strm.next_in = (BYTE const*)ress->readCtx->srcBuffer; + strm.avail_in = ress->readCtx->srcBufferLoaded; + } + + { + size_t const availBefore = strm.avail_in; + ret = lzma_code(&strm, action); + ReadPool_consumeBytes(ress->readCtx, availBefore - strm.avail_in); } - ret = lzma_code(&strm, action); if (ret != LZMA_OK && ret != LZMA_STREAM_END) EXM_THROW(84, "zstd: %s: lzma_code encoding error %d", srcFileName, ret); - { size_t const compBytes = ress->dstBufferSize - strm.avail_out; + { size_t const compBytes = writeJob->bufferSize - strm.avail_out; if (compBytes) { - if (fwrite(ress->dstBuffer, 1, compBytes, ress->dstFile) != compBytes) - EXM_THROW(85, "Write error : %s", strerror(errno)); + writeJob->usedBufferSize = compBytes; + WritePool_enqueueAndReacquireWriteJob(&writeJob); outFileSize += compBytes; - strm.next_out = (BYTE*)ress->dstBuffer; - strm.avail_out = ress->dstBufferSize; + strm.next_out = (Bytef*)writeJob->buffer; + strm.avail_out = writeJob->bufferSize; } } if (srcFileSize == UTIL_FILESIZE_UNKNOWN) DISPLAYUPDATE(2, "\rRead : %u MB ==> %.2f%%", @@ -1105,6 +1115,9 @@ FIO_compressLzmaFrame(cRess_t* ress, lzma_end(&strm); *readsize = inFileSize; + WritePool_releaseIoJob(writeJob); + WritePool_sparseWriteEnd(ress->writeCtx); + return outFileSize; } #endif @@ -1130,13 +1143,15 @@ FIO_compressLz4Frame(cRess_t* ress, LZ4F_preferences_t prefs; LZ4F_compressionContext_t ctx; + io_job_t *writeJob = WritePool_acquireJob(ress->writeCtx); + LZ4F_errorCode_t const errorCode = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION); if (LZ4F_isError(errorCode)) EXM_THROW(31, "zstd: failed to create lz4 compression context"); memset(&prefs, 0, sizeof(prefs)); - assert(blockSize <= ress->srcBufferSize); + assert(blockSize <= ress->readCtx->srcBufferBaseSize); prefs.autoFlush = 1; prefs.compressionLevel = compressionLevel; @@ -1146,27 +1161,26 @@ FIO_compressLz4Frame(cRess_t* ress, #if LZ4_VERSION_NUMBER >= 10600 prefs.frameInfo.contentSize = (srcFileSize==UTIL_FILESIZE_UNKNOWN) ? 0 : srcFileSize; #endif - assert(LZ4F_compressBound(blockSize, &prefs) <= ress->dstBufferSize); + assert(LZ4F_compressBound(blockSize, &prefs) <= writeJob->bufferSize); { size_t readSize; - size_t headerSize = LZ4F_compressBegin(ctx, ress->dstBuffer, ress->dstBufferSize, &prefs); + size_t headerSize = LZ4F_compressBegin(ctx, writeJob->buffer, writeJob->bufferSize, &prefs); if (LZ4F_isError(headerSize)) EXM_THROW(33, "File header generation failed : %s", LZ4F_getErrorName(headerSize)); - if (fwrite(ress->dstBuffer, 1, headerSize, ress->dstFile) != headerSize) - EXM_THROW(34, "Write error : %s (cannot write header)", strerror(errno)); + writeJob->usedBufferSize = headerSize; + WritePool_enqueueAndReacquireWriteJob(&writeJob); outFileSize += headerSize; /* Read first block */ - readSize = fread(ress->srcBuffer, (size_t)1, (size_t)blockSize, ress->srcFile); + readSize = ReadPool_fillBuffer(ress->readCtx, blockSize); inFileSize += readSize; /* Main Loop */ - while (readSize>0) { - size_t const outSize = LZ4F_compressUpdate(ctx, - ress->dstBuffer, ress->dstBufferSize, - ress->srcBuffer, readSize, NULL); + while (ress->readCtx->srcBufferLoaded) { + size_t const outSize = LZ4F_compressUpdate(ctx, writeJob->buffer, writeJob->bufferSize, + ress->readCtx->srcBuffer, ress->readCtx->srcBufferLoaded, NULL); if (LZ4F_isError(outSize)) EXM_THROW(35, "zstd: %s: lz4 compression failed : %s", srcFileName, LZ4F_getErrorName(outSize)); @@ -1182,33 +1196,30 @@ FIO_compressLz4Frame(cRess_t* ress, } /* Write Block */ - { size_t const sizeCheck = fwrite(ress->dstBuffer, 1, outSize, ress->dstFile); - if (sizeCheck != outSize) - EXM_THROW(36, "Write error : %s", strerror(errno)); - } + writeJob->usedBufferSize = outSize; + WritePool_enqueueAndReacquireWriteJob(&writeJob); /* Read next block */ - readSize = fread(ress->srcBuffer, (size_t)1, (size_t)blockSize, ress->srcFile); + ReadPool_consumeBytes(ress->readCtx, ress->readCtx->srcBufferLoaded); + readSize = ReadPool_fillBuffer(ress->readCtx, blockSize); inFileSize += readSize; } - if (ferror(ress->srcFile)) EXM_THROW(37, "Error reading %s ", srcFileName); /* End of Stream mark */ - headerSize = LZ4F_compressEnd(ctx, ress->dstBuffer, ress->dstBufferSize, NULL); + headerSize = LZ4F_compressEnd(ctx, writeJob->buffer, writeJob->bufferSize, NULL); if (LZ4F_isError(headerSize)) EXM_THROW(38, "zstd: %s: lz4 end of file generation failed : %s", srcFileName, LZ4F_getErrorName(headerSize)); - { size_t const sizeCheck = fwrite(ress->dstBuffer, 1, headerSize, ress->dstFile); - if (sizeCheck != headerSize) - EXM_THROW(39, "Write error : %s (cannot write end of stream)", - strerror(errno)); - } + writeJob->usedBufferSize = headerSize; + WritePool_enqueueAndReacquireWriteJob(&writeJob); outFileSize += headerSize; } *readsize = inFileSize; LZ4F_freeCompressionContext(ctx); + WritePool_releaseIoJob(writeJob); + WritePool_sparseWriteEnd(ress->writeCtx); return outFileSize; } @@ -1223,8 +1234,8 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, int compressionLevel, U64* readsize) { cRess_t const ress = *ressPtr; - FILE* const srcFile = ress.srcFile; - FILE* const dstFile = ress.dstFile; + io_job_t *writeJob = WritePool_acquireJob(ressPtr->writeCtx); + U64 compressedfilesize = 0; ZSTD_EndDirective directive = ZSTD_e_continue; U64 pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; @@ -1247,9 +1258,9 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, pledgedSrcSize = fileSize; CHECK(ZSTD_CCtx_setPledgedSrcSize(ress.cctx, fileSize)); } else if (prefs->streamSrcSize > 0) { - /* unknown source size; use the declared stream size */ - pledgedSrcSize = prefs->streamSrcSize; - CHECK( ZSTD_CCtx_setPledgedSrcSize(ress.cctx, prefs->streamSrcSize) ); + /* unknown source size; use the declared stream size */ + pledgedSrcSize = prefs->streamSrcSize; + CHECK( ZSTD_CCtx_setPledgedSrcSize(ress.cctx, prefs->streamSrcSize) ); } { @@ -1269,22 +1280,23 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, do { size_t stillToFlush; /* Fill input Buffer */ - size_t const inSize = fread(ress.srcBuffer, (size_t)1, ress.srcBufferSize, srcFile); - ZSTD_inBuffer inBuff = { ress.srcBuffer, inSize, 0 }; + size_t const inSize = ReadPool_fillBuffer(ress.readCtx, ZSTD_CStreamInSize()); + ZSTD_inBuffer inBuff = { ress.readCtx->srcBuffer, ress.readCtx->srcBufferLoaded, 0 }; DISPLAYLEVEL(6, "fread %u bytes from source \n", (unsigned)inSize); *readsize += inSize; - if ((inSize == 0) || (*readsize == fileSize)) + if ((ress.readCtx->srcBufferLoaded == 0) || (*readsize == fileSize)) directive = ZSTD_e_end; stillToFlush = 1; while ((inBuff.pos != inBuff.size) /* input buffer must be entirely ingested */ - || (directive == ZSTD_e_end && stillToFlush != 0) ) { + || (directive == ZSTD_e_end && stillToFlush != 0) ) { size_t const oldIPos = inBuff.pos; - ZSTD_outBuffer outBuff = { ress.dstBuffer, ress.dstBufferSize, 0 }; + ZSTD_outBuffer outBuff= { writeJob->buffer, writeJob->bufferSize, 0 }; size_t const toFlushNow = ZSTD_toFlushNow(ress.cctx); CHECK_V(stillToFlush, ZSTD_compressStream2(ress.cctx, &outBuff, &inBuff, directive)); + ReadPool_consumeBytes(ress.readCtx, inBuff.pos - oldIPos); /* count stats */ inputPresented++; @@ -1293,12 +1305,10 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, /* Write compressed stream */ DISPLAYLEVEL(6, "ZSTD_compress_generic(end:%u) => input pos(%u)<=(%u)size ; output generated %u bytes \n", - (unsigned)directive, (unsigned)inBuff.pos, (unsigned)inBuff.size, (unsigned)outBuff.pos); + (unsigned)directive, (unsigned)inBuff.pos, (unsigned)inBuff.size, (unsigned)outBuff.pos); if (outBuff.pos) { - size_t const sizeCheck = fwrite(ress.dstBuffer, 1, outBuff.pos, dstFile); - if (sizeCheck != outBuff.pos) - EXM_THROW(25, "Write error : %s (cannot write compressed block)", - strerror(errno)); + writeJob->usedBufferSize = outBuff.pos; + WritePool_enqueueAndReacquireWriteJob(&writeJob); compressedfilesize += outBuff.pos; } @@ -1313,11 +1323,11 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, /* display progress notifications */ if (g_display_prefs.displayLevel >= 3) { DISPLAYUPDATE(3, "\r(L%i) Buffered :%6.*f%4s - Consumed :%6.*f%4s - Compressed :%6.*f%4s => %.2f%% ", - compressionLevel, - buffered_hrs.precision, buffered_hrs.value, buffered_hrs.suffix, - consumed_hrs.precision, consumed_hrs.value, consumed_hrs.suffix, - produced_hrs.precision, produced_hrs.value, produced_hrs.suffix, - cShare ); + compressionLevel, + buffered_hrs.precision, buffered_hrs.value, buffered_hrs.suffix, + consumed_hrs.precision, consumed_hrs.value, consumed_hrs.suffix, + produced_hrs.precision, produced_hrs.value, produced_hrs.suffix, + cShare ); } else if (g_display_prefs.displayLevel >= 2 || g_display_prefs.progressSetting == FIO_ps_always) { /* Require level 2 or forcibly displayed progress counter for summarized updates */ DISPLAYLEVEL(1, "\r%79s\r", ""); /* Clear out the current displayed line */ @@ -1327,15 +1337,15 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, if (srcFileNameSize > 18) { const char* truncatedSrcFileName = srcFileName + srcFileNameSize - 15; DISPLAYLEVEL(1, "Compress: %u/%u files. Current: ...%s ", - fCtx->currFileIdx+1, fCtx->nbFilesTotal, truncatedSrcFileName); + fCtx->currFileIdx+1, fCtx->nbFilesTotal, truncatedSrcFileName); } else { DISPLAYLEVEL(1, "Compress: %u/%u files. Current: %*s ", - fCtx->currFileIdx+1, fCtx->nbFilesTotal, (int)(18-srcFileNameSize), srcFileName); + fCtx->currFileIdx+1, fCtx->nbFilesTotal, (int)(18-srcFileNameSize), srcFileName); } } DISPLAYLEVEL(1, "Read:%6.*f%4s ", consumed_hrs.precision, consumed_hrs.value, consumed_hrs.suffix); if (fileSize != UTIL_FILESIZE_UNKNOWN) - DISPLAYLEVEL(2, "/%6.*f%4s", file_hrs.precision, file_hrs.value, file_hrs.suffix); + DISPLAYLEVEL(2, "/%6.*f%4s", file_hrs.precision, file_hrs.value, file_hrs.suffix); DISPLAYLEVEL(1, " ==> %2.f%%", cShare); DELAY_NEXT_UPDATE(); } @@ -1356,8 +1366,8 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, * or because input is slow and no job can start while waiting for at least one buffer to be filled. * note : exclude starting part, since currentJobID > 1 */ if ( (zfp.consumed == previous_zfp_update.consumed) /* no data compressed : no data available, or no more buffer to compress to, OR compression is really slow (compression of a single block is slower than update rate)*/ - && (zfp.nbActiveWorkers == 0) /* confirmed : no compression ongoing */ - ) { + && (zfp.nbActiveWorkers == 0) /* confirmed : no compression ongoing */ + ) { DISPLAYLEVEL(6, "all buffers full : compression stopped => slow down \n") speedChange = slower; } @@ -1365,8 +1375,8 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, previous_zfp_update = zfp; if ( (newlyProduced > (newlyFlushed * 9 / 8)) /* compression produces more data than output can flush (though production can be spiky, due to work unit : (N==4)*block sizes) */ - && (flushWaiting == 0) /* flush speed was never slowed by lack of production, so it's operating at max capacity */ - ) { + && (flushWaiting == 0) /* flush speed was never slowed by lack of production, so it's operating at max capacity */ + ) { DISPLAYLEVEL(6, "compression faster than flush (%llu > %llu), and flushed was never slowed down by lack of production => slow down \n", newlyProduced, newlyFlushed); speedChange = slower; } @@ -1390,15 +1400,15 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, previous_zfp_correction = zfp; assert(inputPresented > 0); DISPLAYLEVEL(6, "input blocked %u/%u(%.2f) - ingested:%u vs %u:consumed - flushed:%u vs %u:produced \n", - inputBlocked, inputPresented, (double)inputBlocked/inputPresented*100, - (unsigned)newlyIngested, (unsigned)newlyConsumed, - (unsigned)newlyFlushed, (unsigned)newlyProduced); + inputBlocked, inputPresented, (double)inputBlocked/inputPresented*100, + (unsigned)newlyIngested, (unsigned)newlyConsumed, + (unsigned)newlyFlushed, (unsigned)newlyProduced); if ( (inputBlocked > inputPresented / 8) /* input is waiting often, because input buffers is full : compression or output too slow */ - && (newlyFlushed * 33 / 32 > newlyProduced) /* flush everything that is produced */ - && (newlyIngested * 33 / 32 > newlyConsumed) /* input speed as fast or faster than compression speed */ - ) { + && (newlyFlushed * 33 / 32 > newlyProduced) /* flush everything that is produced */ + && (newlyIngested * 33 / 32 > newlyConsumed) /* input speed as fast or faster than compression speed */ + ) { DISPLAYLEVEL(6, "recommend faster as in(%llu) >= (%llu)comp(%llu) <= out(%llu) \n", - newlyIngested, newlyConsumed, newlyProduced, newlyFlushed); + newlyIngested, newlyConsumed, newlyProduced, newlyFlushed); speedChange = faster; } } @@ -1430,14 +1440,14 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, } /* while ((inBuff.pos != inBuff.size) */ } while (directive != ZSTD_e_end); - if (ferror(srcFile)) { - EXM_THROW(26, "Read error : I/O error"); - } if (fileSize != UTIL_FILESIZE_UNKNOWN && *readsize != fileSize) { EXM_THROW(27, "Read error : Incomplete read : %llu / %llu B", - (unsigned long long)*readsize, (unsigned long long)fileSize); + (unsigned long long)*readsize, (unsigned long long)fileSize); } + WritePool_releaseIoJob(writeJob); + WritePool_sparseWriteEnd(ressPtr->writeCtx); + return compressedfilesize; } @@ -1484,7 +1494,7 @@ FIO_compressFilename_internal(FIO_ctx_t* const fCtx, #else (void)compressionLevel; EXM_THROW(20, "zstd: %s: file cannot be compressed as xz/lzma (zstd compiled without ZSTD_LZMACOMPRESS) -- ignored \n", - srcFileName); + srcFileName); #endif break; @@ -1494,7 +1504,7 @@ FIO_compressFilename_internal(FIO_ctx_t* const fCtx, #else (void)compressionLevel; EXM_THROW(20, "zstd: %s: file cannot be compressed as lz4 (zstd compiled without ZSTD_LZ4COMPRESS) -- ignored \n", - srcFileName); + srcFileName); #endif break; } @@ -1510,17 +1520,17 @@ FIO_compressFilename_internal(FIO_ctx_t* const fCtx, UTIL_HumanReadableSize_t hr_osize = UTIL_makeHumanReadableSize((U64) compressedfilesize); if (readsize == 0) { DISPLAYLEVEL(2,"%-20s : (%6.*f%4s => %6.*f%4s, %s) \n", - srcFileName, - hr_isize.precision, hr_isize.value, hr_isize.suffix, - hr_osize.precision, hr_osize.value, hr_osize.suffix, - dstFileName); + srcFileName, + hr_isize.precision, hr_isize.value, hr_isize.suffix, + hr_osize.precision, hr_osize.value, hr_osize.suffix, + dstFileName); } else { DISPLAYLEVEL(2,"%-20s :%6.2f%% (%6.*f%4s => %6.*f%4s, %s) \n", - srcFileName, - (double)compressedfilesize / (double)readsize * 100, - hr_isize.precision, hr_isize.value, hr_isize.suffix, - hr_osize.precision, hr_osize.value, hr_osize.suffix, - dstFileName); + srcFileName, + (double)compressedfilesize / (double)readsize * 100, + hr_isize.precision, hr_isize.value, hr_isize.suffix, + hr_osize.precision, hr_osize.value, hr_osize.suffix, + dstFileName); } } @@ -1531,14 +1541,14 @@ FIO_compressFilename_internal(FIO_ctx_t* const fCtx, double const timeLength_s = (double)timeLength_ns / 1000000000; double const cpuLoad_pct = (cpuLoad_s / timeLength_s) * 100; DISPLAYLEVEL(4, "%-20s : Completed in %.2f sec (cpu load : %.0f%%)\n", - srcFileName, timeLength_s, cpuLoad_pct); + srcFileName, timeLength_s, cpuLoad_pct); } return 0; } /*! FIO_compressFilename_dstFile() : - * open dstFileName, or pass-through if ress.dstFile != NULL, + * open dstFileName, or pass-through if ress.file != NULL, * then start compression with FIO_compressFilename_internal(). * Manages source removal (--rm) and file permissions transfer. * note : ress.srcFile must be != NULL, @@ -1557,21 +1567,23 @@ static int FIO_compressFilename_dstFile(FIO_ctx_t* const fCtx, int result; stat_t statbuf; int transferMTime = 0; - assert(ress.srcFile != NULL); - if (ress.dstFile == NULL) { + FILE *dstFile; + assert(ReadPool_getFile(ress.readCtx) != NULL); + if (WritePool_getFile(ress.writeCtx) == NULL) { int dstFilePermissions = DEFAULT_FILE_PERMISSIONS; if ( strcmp (srcFileName, stdinmark) - && strcmp (dstFileName, stdoutmark) - && UTIL_stat(srcFileName, &statbuf) - && UTIL_isRegularFileStat(&statbuf) ) { + && strcmp (dstFileName, stdoutmark) + && UTIL_stat(srcFileName, &statbuf) + && UTIL_isRegularFileStat(&statbuf) ) { dstFilePermissions = statbuf.st_mode; transferMTime = 1; } closeDstFile = 1; DISPLAYLEVEL(6, "FIO_compressFilename_dstFile: opening dst: %s \n", dstFileName); - ress.dstFile = FIO_openDstFile(fCtx, prefs, srcFileName, dstFileName, dstFilePermissions); - if (ress.dstFile==NULL) return 1; /* could not open dstFileName */ + dstFile = FIO_openDstFile(fCtx, prefs, srcFileName, dstFileName, dstFilePermissions); + if (dstFile==NULL) return 1; /* could not open dstFileName */ + WritePool_setFile(ress.writeCtx, dstFile); /* Must only be added after FIO_openDstFile() succeeds. * Otherwise we may delete the destination file if it already exists, * and the user presses Ctrl-C when asked if they wish to overwrite. @@ -1582,13 +1594,10 @@ static int FIO_compressFilename_dstFile(FIO_ctx_t* const fCtx, result = FIO_compressFilename_internal(fCtx, prefs, ress, dstFileName, srcFileName, compressionLevel); if (closeDstFile) { - FILE* const dstFile = ress.dstFile; - ress.dstFile = NULL; - clearHandler(); DISPLAYLEVEL(6, "FIO_compressFilename_dstFile: closing dst: %s \n", dstFileName); - if (fclose(dstFile)) { /* error closing dstFile */ + if (WritePool_closeFile(ress.writeCtx)) { /* error closing file */ DISPLAYLEVEL(1, "zstd: %s: %s \n", dstFileName, strerror(errno)); result=1; } @@ -1596,8 +1605,8 @@ static int FIO_compressFilename_dstFile(FIO_ctx_t* const fCtx, UTIL_utime(dstFileName, &statbuf); } if ( (result != 0) /* operation failure */ - && strcmp(dstFileName, stdoutmark) /* special case : don't remove() stdout */ - ) { + && strcmp(dstFileName, stdoutmark) /* special case : don't remove() stdout */ + ) { FIO_removeFile(dstFileName); /* remove compression artefact; note don't do anything special if remove() fails */ } } @@ -1609,16 +1618,16 @@ static int FIO_compressFilename_dstFile(FIO_ctx_t* const fCtx, * Different from the suffixList and should only apply to ZSTD compress operationResult */ static const char *compressedFileExtensions[] = { - ZSTD_EXTENSION, - TZSTD_EXTENSION, - GZ_EXTENSION, - TGZ_EXTENSION, - LZMA_EXTENSION, - XZ_EXTENSION, - TXZ_EXTENSION, - LZ4_EXTENSION, - TLZ4_EXTENSION, - NULL + ZSTD_EXTENSION, + TZSTD_EXTENSION, + GZ_EXTENSION, + TGZ_EXTENSION, + LZMA_EXTENSION, + XZ_EXTENSION, + TXZ_EXTENSION, + LZ4_EXTENSION, + TLZ4_EXTENSION, + NULL }; /*! FIO_compressFilename_srcFile() : @@ -1634,6 +1643,7 @@ FIO_compressFilename_srcFile(FIO_ctx_t* const fCtx, int compressionLevel) { int result; + FILE* srcFile; DISPLAYLEVEL(6, "FIO_compressFilename_srcFile: %s \n", srcFileName); /* ensure src is not a directory */ @@ -1657,23 +1667,23 @@ FIO_compressFilename_srcFile(FIO_ctx_t* const fCtx, return 0; } - ress.srcFile = FIO_openSrcFile(prefs, srcFileName); - if (ress.srcFile == NULL) return 1; /* srcFile could not be opened */ + srcFile = FIO_openSrcFile(prefs, srcFileName); + if (srcFile == NULL) return 1; /* srcFile could not be opened */ + ReadPool_setFile(ress.readCtx, srcFile); result = FIO_compressFilename_dstFile(fCtx, prefs, ress, dstFileName, srcFileName, compressionLevel); + ReadPool_closeFile(ress.readCtx); - fclose(ress.srcFile); - ress.srcFile = NULL; if ( prefs->removeSrcFile /* --rm */ - && result == 0 /* success */ - && strcmp(srcFileName, stdinmark) /* exception : don't erase stdin */ - ) { + && result == 0 /* success */ + && strcmp(srcFileName, stdinmark) /* exception : don't erase stdin */ + ) { /* We must clear the handler, since after this point calling it would * delete both the source and destination files. */ clearHandler(); if (FIO_removeFile(srcFileName)) - EXM_THROW(1, "zstd: %s: %s", srcFileName, strerror(errno)); + EXM_THROW(1, "zstd: %s: %s", srcFileName, strerror(errno)); } return result; } @@ -1804,29 +1814,30 @@ int FIO_compressMultipleFilenames(FIO_ctx_t* const fCtx, int status; int error = 0; cRess_t ress = FIO_createCResources(prefs, dictFileName, - FIO_getLargestFileSize(inFileNamesTable, (unsigned)fCtx->nbFilesTotal), - compressionLevel, comprParams); + FIO_getLargestFileSize(inFileNamesTable, (unsigned)fCtx->nbFilesTotal), + compressionLevel, comprParams); /* init */ assert(outFileName != NULL || suffix != NULL); if (outFileName != NULL) { /* output into a single destination (stdout typically) */ + FILE *dstFile; if (FIO_removeMultiFilesWarning(fCtx, prefs, outFileName, 1 /* displayLevelCutoff */)) { FIO_freeCResources(&ress); return 1; } - ress.dstFile = FIO_openDstFile(fCtx, prefs, NULL, outFileName, DEFAULT_FILE_PERMISSIONS); - if (ress.dstFile == NULL) { /* could not open outFileName */ + dstFile = FIO_openDstFile(fCtx, prefs, NULL, outFileName, DEFAULT_FILE_PERMISSIONS); + if (dstFile == NULL) { /* could not open outFileName */ error = 1; } else { + WritePool_setFile(ress.writeCtx, dstFile); for (; fCtx->currFileIdx < fCtx->nbFilesTotal; ++fCtx->currFileIdx) { status = FIO_compressFilename_srcFile(fCtx, prefs, ress, outFileName, inFileNamesTable[fCtx->currFileIdx], compressionLevel); if (!status) fCtx->nbFilesProcessed++; error |= status; } - if (fclose(ress.dstFile)) - EXM_THROW(29, "Write error (%s) : cannot properly close %s", - strerror(errno), outFileName); - ress.dstFile = NULL; + if (WritePool_closeFile(ress.writeCtx)) + EXM_THROW(29, "Write error (%s) : cannot properly close %s", + strerror(errno), outFileName); } } else { if (outMirroredRootDirName) @@ -1863,10 +1874,10 @@ int FIO_compressMultipleFilenames(FIO_ctx_t* const fCtx, DISPLAYLEVEL(2, "\r%79s\r", ""); DISPLAYLEVEL(2, "%3d files compressed :%.2f%% (%6.*f%4s => %6.*f%4s)\n", - fCtx->nbFilesProcessed, - (double)fCtx->totalBytesOutput/((double)fCtx->totalBytesInput)*100, - hr_isize.precision, hr_isize.value, hr_isize.suffix, - hr_osize.precision, hr_osize.value, hr_osize.suffix); + fCtx->nbFilesProcessed, + (double)fCtx->totalBytesOutput/((double)fCtx->totalBytesInput)*100, + hr_isize.precision, hr_isize.value, hr_isize.suffix, + hr_osize.precision, hr_osize.value, hr_osize.suffix); } FIO_freeCResources(&ress); @@ -1882,13 +1893,10 @@ int FIO_compressMultipleFilenames(FIO_ctx_t* const fCtx, /* ************************************************************************** * Decompression ***************************************************************************/ - typedef struct { - void* srcBuffer; - size_t srcBufferSize; - size_t srcBufferLoaded; ZSTD_DStream* dctx; WritePoolCtx_t *writeCtx; + read_pool_ctx_t *readCtx; } dRess_t; static dRess_t FIO_createDResources(FIO_prefs_t* const prefs, const char* dictFileName) @@ -1902,15 +1910,10 @@ static dRess_t FIO_createDResources(FIO_prefs_t* const prefs, const char* dictFi /* Allocation */ ress.dctx = ZSTD_createDStream(); if (ress.dctx==NULL) - EXM_THROW(60, "Error: %s : can't create ZSTD_DStream", strerror(errno)); + EXM_THROW(60, "Error: %s : can't create ZSTD_DStream", strerror(errno)); CHECK( ZSTD_DCtx_setMaxWindowSize(ress.dctx, prefs->memLimit) ); CHECK( ZSTD_DCtx_setParameter(ress.dctx, ZSTD_d_forceIgnoreChecksum, !prefs->checksumFlag)); - ress.srcBufferSize = ZSTD_DStreamInSize(); - ress.srcBuffer = malloc(ress.srcBufferSize); - if (!ress.srcBuffer) - EXM_THROW(61, "Allocation error : not enough memory"); - /* dictionary */ { void* dictBuffer; size_t const dictBufferSize = FIO_createDictBuffer(&dictBuffer, dictFileName, prefs); @@ -1919,6 +1922,7 @@ static dRess_t FIO_createDResources(FIO_prefs_t* const prefs, const char* dictFi } ress.writeCtx = AIO_WritePool_create(prefs, ZSTD_DStreamOutSize()); + ress.readCtx = ReadPool_create(prefs, ZSTD_DStreamInSize()); return ress; } @@ -1926,47 +1930,31 @@ static dRess_t FIO_createDResources(FIO_prefs_t* const prefs, const char* dictFi static void FIO_freeDResources(dRess_t ress) { CHECK( ZSTD_freeDStream(ress.dctx) ); - free(ress.srcBuffer); AIO_WritePool_free(ress.writeCtx); -} - -/* FIO_consumeDSrcBuffer: - * Consumes len bytes from srcBuffer's start and moves the remaining data and srcBufferLoaded accordingly. */ -static void FIO_consumeDSrcBuffer(dRess_t *ress, size_t len) { - assert(ress->srcBufferLoaded >= len); - ress->srcBufferLoaded -= len; - memmove(ress->srcBuffer, (char *)ress->srcBuffer + len, ress->srcBufferLoaded); + ReadPool_free(ress.readCtx); } /** FIO_passThrough() : just copy input into output, for compatibility with gzip -df mode @return : 0 (no error) */ -static int FIO_passThrough(const FIO_prefs_t* const prefs, - FILE* foutput, FILE* finput, - void* buffer, size_t bufferSize, - size_t alreadyLoaded) +static int FIO_passThrough(dRess_t *ress) { - size_t const blockSize = MIN(64 KB, bufferSize); - size_t readFromInput; - unsigned storedSkips = 0; - - /* assumption : ress->srcBufferLoaded bytes already loaded and stored within buffer */ - { size_t const sizeCheck = fwrite(buffer, 1, alreadyLoaded, foutput); - if (sizeCheck != alreadyLoaded) { - DISPLAYLEVEL(1, "Pass-through write error : %s\n", strerror(errno)); - return 1; - } } - - do { - readFromInput = fread(buffer, 1, blockSize, finput); - storedSkips = AIO_fwriteSparse(foutput, buffer, readFromInput, prefs, storedSkips); - } while (readFromInput == blockSize); - if (ferror(finput)) { - DISPLAYLEVEL(1, "Pass-through read error : %s\n", strerror(errno)); - return 1; + size_t const blockSize = MIN(MIN(64 KB, ZSTD_DStreamInSize()), ZSTD_DStreamOutSize()); + IOJob_t *writeJob = AIO_WritePool_acquireJob(ress->writeCtx); + ReadPool_fillBuffer(ress->readCtx, blockSize); + + while(ress->readCtx->srcBufferLoaded) { + size_t writeSize; + ReadPool_fillBuffer(ress->readCtx, blockSize); + writeSize = MIN(blockSize, ress->readCtx->srcBufferLoaded); + assert(writeSize <= writeJob->bufferSize); + memcpy(writeJob->buffer, ress->readCtx->srcBuffer, writeSize); + writeJob->usedBufferSize = writeSize; + AIO_WritePool_enqueueAndReacquireWriteJob(&writeJob); + ReadPool_consumeBytes(ress->readCtx, writeSize); } - assert(feof(finput)); - - AIO_fwriteSparseEnd(prefs, foutput, storedSkips); + assert(ress->readCtx->reachedEof); + AIO_WritePool_releaseIoJob(writeJob); + AIO_WritePool_sparseWriteEnd(ress->writeCtx); return 0; } @@ -1984,22 +1972,22 @@ FIO_zstdErrorHelp(const FIO_prefs_t* const prefs, return; /* Try to decode the frame header */ - err = ZSTD_getFrameHeader(&header, ress->srcBuffer, ress->srcBufferLoaded); + err = ZSTD_getFrameHeader(&header, ress->readCtx->srcBuffer, ress->readCtx->srcBufferLoaded); if (err == 0) { unsigned long long const windowSize = header.windowSize; unsigned const windowLog = FIO_highbit64(windowSize) + ((windowSize & (windowSize - 1)) != 0); assert(prefs->memLimit > 0); DISPLAYLEVEL(1, "%s : Window size larger than maximum : %llu > %u \n", - srcFileName, windowSize, prefs->memLimit); + srcFileName, windowSize, prefs->memLimit); if (windowLog <= ZSTD_WINDOWLOG_MAX) { unsigned const windowMB = (unsigned)((windowSize >> 20) + ((windowSize & ((1 MB) - 1)) != 0)); assert(windowSize < (U64)(1ULL << 52)); /* ensure now overflow for windowMB */ DISPLAYLEVEL(1, "%s : Use --long=%u or --memory=%uMB \n", - srcFileName, windowLog, windowMB); + srcFileName, windowLog, windowMB); return; - } } + } } DISPLAYLEVEL(1, "%s : Window log larger than ZSTD_WINDOWLOG_MAX=%u; not supported \n", - srcFileName, ZSTD_WINDOWLOG_MAX); + srcFileName, ZSTD_WINDOWLOG_MAX); } /** FIO_decompressFrame() : @@ -2007,7 +1995,7 @@ FIO_zstdErrorHelp(const FIO_prefs_t* const prefs, */ #define FIO_ERROR_FRAME_DECODING ((unsigned long long)(-2)) static unsigned long long -FIO_decompressZstdFrame(FIO_ctx_t* const fCtx, dRess_t* ress, FILE* finput, +FIO_decompressZstdFrame(FIO_ctx_t* const fCtx, dRess_t* ress, const FIO_prefs_t* const prefs, const char* srcFileName, U64 alreadyDecoded) /* for multi-frames streams */ @@ -2023,23 +2011,19 @@ FIO_decompressZstdFrame(FIO_ctx_t* const fCtx, dRess_t* ress, FILE* finput, ZSTD_DCtx_reset(ress->dctx, ZSTD_reset_session_only); /* Header loading : ensures ZSTD_getFrameHeader() will succeed */ - { size_t const toDecode = ZSTD_FRAMEHEADERSIZE_MAX; - if (ress->srcBufferLoaded < toDecode) { - size_t const toRead = toDecode - ress->srcBufferLoaded; - void* const startPosition = (char*)ress->srcBuffer + ress->srcBufferLoaded; - ress->srcBufferLoaded += fread(startPosition, 1, toRead, finput); - } } + if (ress->readCtx->srcBufferLoaded < ZSTD_FRAMEHEADERSIZE_MAX) + ReadPool_fillBuffer(ress->readCtx, ZSTD_FRAMEHEADERSIZE_MAX); /* Main decompression Loop */ while (1) { - ZSTD_inBuffer inBuff = { ress->srcBuffer, ress->srcBufferLoaded, 0 }; + ZSTD_inBuffer inBuff = { ress->readCtx->srcBuffer, ress->readCtx->srcBufferLoaded, 0 }; ZSTD_outBuffer outBuff= { writeJob->buffer, writeJob->bufferSize, 0 }; size_t const readSizeHint = ZSTD_decompressStream(ress->dctx, &outBuff, &inBuff); const int displayLevel = (g_display_prefs.progressSetting == FIO_ps_always) ? 1 : 2; UTIL_HumanReadableSize_t const hrs = UTIL_makeHumanReadableSize(alreadyDecoded+frameSize); if (ZSTD_isError(readSizeHint)) { DISPLAYLEVEL(1, "%s : Decoding error (36) : %s \n", - srcFileName, ZSTD_getErrorName(readSizeHint)); + srcFileName, ZSTD_getErrorName(readSizeHint)); FIO_zstdErrorHelp(prefs, ress, readSizeHint, srcFileName); AIO_WritePool_releaseIoJob(writeJob); return FIO_ERROR_FRAME_DECODING; @@ -2054,33 +2038,31 @@ FIO_decompressZstdFrame(FIO_ctx_t* const fCtx, dRess_t* ress, FILE* finput, if (srcFileNameSize > 18) { const char* truncatedSrcFileName = srcFileName + srcFileNameSize - 15; DISPLAYUPDATE(displayLevel, "\rDecompress: %2u/%2u files. Current: ...%s : %.*f%s... ", - fCtx->currFileIdx+1, fCtx->nbFilesTotal, truncatedSrcFileName, hrs.precision, hrs.value, hrs.suffix); + fCtx->currFileIdx+1, fCtx->nbFilesTotal, truncatedSrcFileName, hrs.precision, hrs.value, hrs.suffix); } else { DISPLAYUPDATE(displayLevel, "\rDecompress: %2u/%2u files. Current: %s : %.*f%s... ", - fCtx->currFileIdx+1, fCtx->nbFilesTotal, srcFileName, hrs.precision, hrs.value, hrs.suffix); + fCtx->currFileIdx+1, fCtx->nbFilesTotal, srcFileName, hrs.precision, hrs.value, hrs.suffix); } } else { DISPLAYUPDATE(displayLevel, "\r%-20.20s : %.*f%s... ", - srcFileName, hrs.precision, hrs.value, hrs.suffix); + srcFileName, hrs.precision, hrs.value, hrs.suffix); } - FIO_consumeDSrcBuffer(ress, inBuff.pos); + ReadPool_consumeBytes(ress->readCtx, inBuff.pos); if (readSizeHint == 0) break; /* end of frame */ /* Fill input buffer */ - { size_t const toDecode = MIN(readSizeHint, ress->srcBufferSize); /* support large skippable frames */ - if (ress->srcBufferLoaded < toDecode) { - size_t const toRead = toDecode - ress->srcBufferLoaded; /* > 0 */ - void* const startPosition = (char*)ress->srcBuffer + ress->srcBufferLoaded; - size_t const readSize = fread(startPosition, 1, toRead, finput); + { size_t const toDecode = MIN(readSizeHint, ZSTD_DStreamInSize()); /* support large skippable frames */ + if (ress->readCtx->srcBufferLoaded < toDecode) { + size_t const readSize = ReadPool_fillBuffer(ress->readCtx, toDecode); if (readSize==0) { DISPLAYLEVEL(1, "%s : Read error (39) : premature end \n", - srcFileName); + srcFileName); + WritePool_releaseIoJob(writeJob); return FIO_ERROR_FRAME_DECODING; } - ress->srcBufferLoaded += readSize; - } } } + } } } AIO_WritePool_releaseIoJob(writeJob); AIO_WritePool_sparseWriteEnd(ress->writeCtx); @@ -2091,7 +2073,7 @@ FIO_decompressZstdFrame(FIO_ctx_t* const fCtx, dRess_t* ress, FILE* finput, #ifdef ZSTD_GZDECOMPRESS static unsigned long long -FIO_decompressGzFrame(dRess_t* ress, FILE* srcFile, const char* srcFileName) +FIO_decompressGzFrame(dRess_t* ress, const char* srcFileName) { unsigned long long outFileSize = 0; z_stream strm; @@ -2111,16 +2093,16 @@ FIO_decompressGzFrame(dRess_t* ress, FILE* srcFile, const char* srcFileName) writeJob = AIO_WritePool_acquireJob(ress->writeCtx); strm.next_out = (Bytef*)writeJob->buffer; strm.avail_out = (uInt)writeJob->bufferSize; - strm.avail_in = (uInt)ress->srcBufferLoaded; - strm.next_in = (z_const unsigned char*)ress->srcBuffer; + strm.avail_in = (uInt)ress->readCtx->srcBufferLoaded; + strm.next_in = (z_const unsigned char*)ress->readCtx->srcBuffer; for ( ; ; ) { int ret; if (strm.avail_in == 0) { - ress->srcBufferLoaded = fread(ress->srcBuffer, 1, ress->srcBufferSize, srcFile); - if (ress->srcBufferLoaded == 0) flush = Z_FINISH; - strm.next_in = (z_const unsigned char*)ress->srcBuffer; - strm.avail_in = (uInt)ress->srcBufferLoaded; + ReadPool_consumeAndRefill(ress->readCtx); + if (ress->readCtx->srcBufferLoaded == 0) flush = Z_FINISH; + strm.next_in = (z_const unsigned char*)ress->readCtx->srcBuffer; + strm.avail_in = (uInt)ress->readCtx->srcBufferLoaded; } ret = inflate(&strm, flush); if (ret == Z_BUF_ERROR) { @@ -2143,10 +2125,10 @@ FIO_decompressGzFrame(dRess_t* ress, FILE* srcFile, const char* srcFileName) if (ret == Z_STREAM_END) break; } - FIO_consumeDSrcBuffer(ress, ress->srcBufferLoaded - strm.avail_in); + ReadPool_consumeBytes(ress->readCtx, ress->readCtx->srcBufferLoaded - strm.avail_in); if ( (inflateEnd(&strm) != Z_OK) /* release resources ; error detected */ - && (decodingError==0) ) { + && (decodingError==0) ) { DISPLAYLEVEL(1, "zstd: %s: inflateEnd error \n", srcFileName); decodingError = 1; } @@ -2158,7 +2140,7 @@ FIO_decompressGzFrame(dRess_t* ress, FILE* srcFile, const char* srcFileName) #ifdef ZSTD_LZMADECOMPRESS static unsigned long long -FIO_decompressLzmaFrame(dRess_t* ress, FILE* srcFile, +FIO_decompressLzmaFrame(dRess_t* ress, const char* srcFileName, int plain_lzma) { unsigned long long outFileSize = 0; @@ -2186,16 +2168,16 @@ FIO_decompressLzmaFrame(dRess_t* ress, FILE* srcFile, writeJob = AIO_WritePool_acquireJob(ress->writeCtx); strm.next_out = (Bytef*)writeJob->buffer; strm.avail_out = (uInt)writeJob->bufferSize; - strm.next_in = (BYTE const*)ress->srcBuffer; - strm.avail_in = ress->srcBufferLoaded; + strm.next_in = (BYTE const*)ress->readCtx->srcBuffer; + strm.avail_in = ress->readCtx->srcBufferLoaded; for ( ; ; ) { lzma_ret ret; if (strm.avail_in == 0) { - ress->srcBufferLoaded = fread(ress->srcBuffer, 1, ress->srcBufferSize, srcFile); - if (ress->srcBufferLoaded == 0) action = LZMA_FINISH; - strm.next_in = (BYTE const*)ress->srcBuffer; - strm.avail_in = ress->srcBufferLoaded; + ReadPool_consumeAndRefill(ress->readCtx); + if (ress->readCtx->srcBufferLoaded == 0) action = LZMA_FINISH; + strm.next_in = (BYTE const*)ress->readCtx->srcBuffer; + strm.avail_in = ress->readCtx->srcBufferLoaded; } ret = lzma_code(&strm, action); @@ -2219,7 +2201,7 @@ FIO_decompressLzmaFrame(dRess_t* ress, FILE* srcFile, if (ret == LZMA_STREAM_END) break; } - FIO_consumeDSrcBuffer(ress, ress->srcBufferLoaded - strm.avail_in); + ReadPool_consumeBytes(ress->readCtx, ress->readCtx->srcBufferLoaded - strm.avail_in); lzma_end(&strm); AIO_WritePool_releaseIoJob(writeJob); AIO_WritePool_sparseWriteEnd(ress->writeCtx); @@ -2229,8 +2211,7 @@ FIO_decompressLzmaFrame(dRess_t* ress, FILE* srcFile, #ifdef ZSTD_LZ4DECOMPRESS static unsigned long long -FIO_decompressLz4Frame(dRess_t* ress, FILE* srcFile, - const char* srcFileName) +FIO_decompressLz4Frame(dRess_t* ress, const char* srcFileName) { unsigned long long filesize = 0; LZ4F_errorCode_t nextToLoad = 4; @@ -2248,34 +2229,27 @@ FIO_decompressLz4Frame(dRess_t* ress, FILE* srcFile, /* Main Loop */ for (;nextToLoad;) { - size_t readSize; size_t pos = 0; size_t decodedBytes = writeJob->bufferSize; int fullBufferDecoded = 0; /* Read input */ - nextToLoad = MIN(nextToLoad, ress->srcBufferSize-ress->srcBufferLoaded); - readSize = fread((char *)ress->srcBuffer + ress->srcBufferLoaded, 1, nextToLoad, srcFile); - if(!readSize && ferror(srcFile)) { - DISPLAYLEVEL(1, "zstd: %s: read error \n", srcFileName); - decodingError=1; - break; - } - if(!readSize && !ress->srcBufferLoaded) break; /* reached end of file */ - ress->srcBufferLoaded += readSize; + ReadPool_fillBuffer(ress->readCtx, nextToLoad); + if(!ress->readCtx->srcBufferLoaded) break; /* reached end of file */ - while ((pos < ress->srcBufferLoaded) || fullBufferDecoded) { /* still to read, or still to flush */ + while ((pos < ress->readCtx->srcBufferLoaded) || fullBufferDecoded) { /* still to read, or still to flush */ /* Decode Input (at least partially) */ - size_t remaining = ress->srcBufferLoaded - pos; + size_t remaining = ress->readCtx->srcBufferLoaded - pos; decodedBytes = writeJob->bufferSize; - nextToLoad = LZ4F_decompress(dCtx, writeJob->buffer, &decodedBytes, (char*)(ress->srcBuffer)+pos, &remaining, NULL); + nextToLoad = LZ4F_decompress(dCtx, writeJob->buffer, &decodedBytes, (char*)(ress->readCtx->srcBuffer)+pos, + &remaining, NULL); if (LZ4F_isError(nextToLoad)) { DISPLAYLEVEL(1, "zstd: %s: lz4 decompression error : %s \n", srcFileName, LZ4F_getErrorName(nextToLoad)); decodingError = 1; nextToLoad = 0; break; } pos += remaining; - assert(pos <= ress->srcBufferLoaded); + assert(pos <= ress->readCtx->srcBufferLoaded); fullBufferDecoded = decodedBytes == writeJob->bufferSize; /* Write Block */ @@ -2290,7 +2264,7 @@ FIO_decompressLz4Frame(dRess_t* ress, FILE* srcFile, if (!nextToLoad) break; } - FIO_consumeDSrcBuffer(ress, pos); + ReadPool_consumeBytes(ress->readCtx, pos); } if (nextToLoad!=0) { DISPLAYLEVEL(1, "zstd: %s: unfinished lz4 stream \n", srcFileName); @@ -2314,23 +2288,20 @@ FIO_decompressLz4Frame(dRess_t* ress, FILE* srcFile, * 1 : error */ static int FIO_decompressFrames(FIO_ctx_t* const fCtx, - dRess_t ress, FILE* srcFile, - const FIO_prefs_t* const prefs, - const char* dstFileName, const char* srcFileName) + dRess_t ress, const FIO_prefs_t* const prefs, + const char* dstFileName, const char* srcFileName) { unsigned readSomething = 0; unsigned long long filesize = 0; - assert(srcFile != NULL); /* for each frame */ for ( ; ; ) { /* check magic number -> version */ size_t const toRead = 4; - const BYTE* const buf = (const BYTE*)ress.srcBuffer; - if (ress.srcBufferLoaded < toRead) /* load up to 4 bytes for header */ - ress.srcBufferLoaded += fread((char*)ress.srcBuffer + ress.srcBufferLoaded, - (size_t)1, toRead - ress.srcBufferLoaded, srcFile); - if (ress.srcBufferLoaded==0) { + const BYTE* buf; + ReadPool_fillBuffer(ress.readCtx, toRead); + buf = (const BYTE*)ress.readCtx->srcBuffer; + if (ress.readCtx->srcBufferLoaded==0) { if (readSomething==0) { /* srcFile is empty (which is invalid) */ DISPLAYLEVEL(1, "zstd: %s: unexpected end of file \n", srcFileName); return 1; @@ -2338,17 +2309,17 @@ static int FIO_decompressFrames(FIO_ctx_t* const fCtx, break; /* no more input */ } readSomething = 1; /* there is at least 1 byte in srcFile */ - if (ress.srcBufferLoaded < toRead) { + if (ress.readCtx->srcBufferLoaded < toRead) { DISPLAYLEVEL(1, "zstd: %s: unknown header \n", srcFileName); return 1; } - if (ZSTD_isFrame(buf, ress.srcBufferLoaded)) { - unsigned long long const frameSize = FIO_decompressZstdFrame(fCtx, &ress, srcFile, prefs, srcFileName, filesize); + if (ZSTD_isFrame(buf, ress.readCtx->srcBufferLoaded)) { + unsigned long long const frameSize = FIO_decompressZstdFrame(fCtx, &ress, prefs, srcFileName, filesize); if (frameSize == FIO_ERROR_FRAME_DECODING) return 1; filesize += frameSize; } else if (buf[0] == 31 && buf[1] == 139) { /* gz magic number */ #ifdef ZSTD_GZDECOMPRESS - unsigned long long const frameSize = FIO_decompressGzFrame(&ress, srcFile, srcFileName); + unsigned long long const frameSize = FIO_decompressGzFrame(&ress, srcFileName); if (frameSize == FIO_ERROR_FRAME_DECODING) return 1; filesize += frameSize; #else @@ -2356,9 +2327,9 @@ static int FIO_decompressFrames(FIO_ctx_t* const fCtx, return 1; #endif } else if ((buf[0] == 0xFD && buf[1] == 0x37) /* xz magic number */ - || (buf[0] == 0x5D && buf[1] == 0x00)) { /* lzma header (no magic number) */ + || (buf[0] == 0x5D && buf[1] == 0x00)) { /* lzma header (no magic number) */ #ifdef ZSTD_LZMADECOMPRESS - unsigned long long const frameSize = FIO_decompressLzmaFrame(&ress, srcFile, srcFileName, buf[0] != 0xFD); + unsigned long long const frameSize = FIO_decompressLzmaFrame(&ress, srcFileName, buf[0] != 0xFD); if (frameSize == FIO_ERROR_FRAME_DECODING) return 1; filesize += frameSize; #else @@ -2367,7 +2338,7 @@ static int FIO_decompressFrames(FIO_ctx_t* const fCtx, #endif } else if (MEM_readLE32(buf) == LZ4_MAGICNUMBER) { #ifdef ZSTD_LZ4DECOMPRESS - unsigned long long const frameSize = FIO_decompressLz4Frame(&ress, srcFile, srcFileName); + unsigned long long const frameSize = FIO_decompressLz4Frame(&ress, srcFileName); if (frameSize == FIO_ERROR_FRAME_DECODING) return 1; filesize += frameSize; #else @@ -2375,14 +2346,11 @@ static int FIO_decompressFrames(FIO_ctx_t* const fCtx, return 1; #endif } else if ((prefs->overwrite) && !strcmp (dstFileName, stdoutmark)) { /* pass-through mode */ - return FIO_passThrough(prefs, - AIO_WritePool_getFile(ress.writeCtx), srcFile, - ress.srcBuffer, ress.srcBufferSize, - ress.srcBufferLoaded); + return FIO_passThrough(&ress); } else { DISPLAYLEVEL(1, "zstd: %s: unsupported format \n", srcFileName); return 1; - } } /* for each frame */ + } } /* for each frame */ /* Final Status */ fCtx->totalBytesOutput += (size_t)filesize; @@ -2398,15 +2366,14 @@ static int FIO_decompressFrames(FIO_ctx_t* const fCtx, } /** FIO_decompressDstFile() : - open `dstFileName`, - or path-through if ress.dstFile is already != 0, + open `dstFileName`, or pass-through if writeCtx's file is already != 0, then start decompression process (FIO_decompressFrames()). @return : 0 : OK 1 : operation aborted */ static int FIO_decompressDstFile(FIO_ctx_t* const fCtx, FIO_prefs_t* const prefs, - dRess_t ress, FILE* srcFile, + dRess_t ress, const char* dstFileName, const char* srcFileName) { int result; @@ -2418,9 +2385,9 @@ static int FIO_decompressDstFile(FIO_ctx_t* const fCtx, FILE *dstFile; int dstFilePermissions = DEFAULT_FILE_PERMISSIONS; if ( strcmp(srcFileName, stdinmark) /* special case : don't transfer permissions from stdin */ - && strcmp(dstFileName, stdoutmark) - && UTIL_stat(srcFileName, &statbuf) - && UTIL_isRegularFileStat(&statbuf) ) { + && strcmp(dstFileName, stdoutmark) + && UTIL_stat(srcFileName, &statbuf) + && UTIL_isRegularFileStat(&statbuf) ) { dstFilePermissions = statbuf.st_mode; transferMTime = 1; } @@ -2438,7 +2405,7 @@ static int FIO_decompressDstFile(FIO_ctx_t* const fCtx, addHandler(dstFileName); } - result = FIO_decompressFrames(fCtx, ress, srcFile, prefs, dstFileName, srcFileName); + result = FIO_decompressFrames(fCtx, ress, prefs, dstFileName, srcFileName); if (releaseDstFile) { clearHandler(); @@ -2452,8 +2419,8 @@ static int FIO_decompressDstFile(FIO_ctx_t* const fCtx, } if ( (result != 0) /* operation failure */ - && strcmp(dstFileName, stdoutmark) /* special case : don't remove() stdout */ - ) { + && strcmp(dstFileName, stdoutmark) /* special case : don't remove() stdout */ + ) { FIO_removeFile(dstFileName); /* remove decompression artefact; note: don't do anything special if remove() fails */ } } @@ -2479,9 +2446,11 @@ static int FIO_decompressSrcFile(FIO_ctx_t* const fCtx, FIO_prefs_t* const prefs srcFile = FIO_openSrcFile(prefs, srcFileName); if (srcFile==NULL) return 1; - ress.srcBufferLoaded = 0; + ReadPool_setFile(ress.readCtx, srcFile); - result = FIO_decompressDstFile(fCtx, prefs, ress, srcFile, dstFileName, srcFileName); + result = FIO_decompressDstFile(fCtx, prefs, ress, dstFileName, srcFileName); + + ReadPool_setFile(ress.readCtx, NULL); /* Close file */ if (fclose(srcFile)) { @@ -2489,8 +2458,8 @@ static int FIO_decompressSrcFile(FIO_ctx_t* const fCtx, FIO_prefs_t* const prefs return 1; } if ( prefs->removeSrcFile /* --rm */ - && (result==0) /* decompression successful */ - && strcmp(srcFileName, stdinmark) ) /* not stdin */ { + && (result==0) /* decompression successful */ + && strcmp(srcFileName, stdinmark) ) /* not stdin */ { /* We must clear the handler, since after this point calling it would * delete both the source and destination files. */ @@ -2499,7 +2468,7 @@ static int FIO_decompressSrcFile(FIO_ctx_t* const fCtx, FIO_prefs_t* const prefs /* failed to remove src file */ DISPLAYLEVEL(1, "zstd: %s: %s \n", srcFileName, strerror(errno)); return 1; - } } + } } return result; } @@ -2518,37 +2487,37 @@ int FIO_decompressFilename(FIO_ctx_t* const fCtx, FIO_prefs_t* const prefs, } static const char *suffixList[] = { - ZSTD_EXTENSION, - TZSTD_EXTENSION, + ZSTD_EXTENSION, + TZSTD_EXTENSION, #ifndef ZSTD_NODECOMPRESS - ZSTD_ALT_EXTENSION, + ZSTD_ALT_EXTENSION, #endif #ifdef ZSTD_GZDECOMPRESS - GZ_EXTENSION, - TGZ_EXTENSION, + GZ_EXTENSION, + TGZ_EXTENSION, #endif #ifdef ZSTD_LZMADECOMPRESS - LZMA_EXTENSION, + LZMA_EXTENSION, XZ_EXTENSION, TXZ_EXTENSION, #endif #ifdef ZSTD_LZ4DECOMPRESS - LZ4_EXTENSION, + LZ4_EXTENSION, TLZ4_EXTENSION, #endif - NULL + NULL }; static const char *suffixListStr = - ZSTD_EXTENSION "/" TZSTD_EXTENSION -#ifdef ZSTD_GZDECOMPRESS - "/" GZ_EXTENSION "/" TGZ_EXTENSION + ZSTD_EXTENSION "/" TZSTD_EXTENSION + #ifdef ZSTD_GZDECOMPRESS + "/" GZ_EXTENSION "/" TGZ_EXTENSION #endif #ifdef ZSTD_LZMADECOMPRESS - "/" LZMA_EXTENSION "/" XZ_EXTENSION "/" TXZ_EXTENSION +"/" LZMA_EXTENSION "/" XZ_EXTENSION "/" TXZ_EXTENSION #endif #ifdef ZSTD_LZ4DECOMPRESS - "/" LZ4_EXTENSION "/" TLZ4_EXTENSION +"/" LZ4_EXTENSION "/" TLZ4_EXTENSION #endif ; @@ -2572,10 +2541,10 @@ FIO_determineDstName(const char* srcFileName, const char* outDirName) const char* const srcSuffix = strrchr(srcFileName, '.'); if (srcSuffix == NULL) { DISPLAYLEVEL(1, - "zstd: %s: unknown suffix (%s expected). " - "Can't derive the output file name. " - "Specify it with -o dstFileName. Ignoring.\n", - srcFileName, suffixListStr); + "zstd: %s: unknown suffix (%s expected). " + "Can't derive the output file name. " + "Specify it with -o dstFileName. Ignoring.\n", + srcFileName, suffixListStr); return NULL; } srcSuffixLen = strlen(srcSuffix); @@ -2591,10 +2560,10 @@ FIO_determineDstName(const char* srcFileName, const char* outDirName) /* check suffix is authorized */ if (sfnSize <= srcSuffixLen || *matchedSuffixPtr == NULL) { DISPLAYLEVEL(1, - "zstd: %s: unknown suffix (%s expected). " - "Can't derive the output file name. " - "Specify it with -o dstFileName. Ignoring.\n", - srcFileName, suffixListStr); + "zstd: %s: unknown suffix (%s expected). " + "Can't derive the output file name. " + "Specify it with -o dstFileName. Ignoring.\n", + srcFileName, suffixListStr); return NULL; } @@ -2616,8 +2585,8 @@ FIO_determineDstName(const char* srcFileName, const char* outDirName) dfnbCapacity = sfnSize + 20; dstFileNameBuffer = (char*)malloc(dfnbCapacity); if (dstFileNameBuffer==NULL) - EXM_THROW(74, "%s : not enough memory for dstFileName", - strerror(errno)); + EXM_THROW(74, "%s : not enough memory for dstFileName", + strerror(errno)); } /* return dst name == src name truncated from suffix */ @@ -2666,8 +2635,8 @@ FIO_decompressMultipleFilenames(FIO_ctx_t* const fCtx, error |= status; } if ((!prefs->testMode) && (AIO_WritePool_closeFile(ress.writeCtx))) - EXM_THROW(72, "Write error : %s : cannot properly close output file", - strerror(errno)); + EXM_THROW(72, "Write error : %s : cannot properly close output file", + strerror(errno)); } else { if (outMirroredRootDirName) UTIL_mirrorSourceFilesDirectories(srcNamesTable, (unsigned)fCtx->nbFilesTotal, outMirroredRootDirName); @@ -2696,7 +2665,7 @@ FIO_decompressMultipleFilenames(FIO_ctx_t* const fCtx, } if (fCtx->nbFilesProcessed >= 1 && fCtx->nbFilesTotal > 1 && fCtx->totalBytesOutput != 0) - DISPLAYLEVEL(2, "%d files decompressed : %6zu bytes total \n", fCtx->nbFilesProcessed, fCtx->totalBytesOutput); + DISPLAYLEVEL(2, "%d files decompressed : %6zu bytes total \n", fCtx->nbFilesProcessed, fCtx->totalBytesOutput); FIO_freeDResources(ress); return error; @@ -2718,11 +2687,11 @@ typedef struct { } fileInfo_t; typedef enum { - info_success=0, - info_frame_error=1, - info_not_zstd=2, - info_file_error=3, - info_truncated_input=4, + info_success=0, + info_frame_error=1, + info_not_zstd=2, + info_file_error=3, + info_truncated_input=4, } InfoError; #define ERROR_IF(c,n,...) { \ @@ -2742,15 +2711,15 @@ FIO_analyzeFrames(fileInfo_t* info, FILE* const srcFile) size_t const numBytesRead = fread(headerBuffer, 1, sizeof(headerBuffer), srcFile); if (numBytesRead < ZSTD_FRAMEHEADERSIZE_MIN(ZSTD_f_zstd1)) { if ( feof(srcFile) - && (numBytesRead == 0) - && (info->compressedSize > 0) - && (info->compressedSize != UTIL_FILESIZE_UNKNOWN) ) { + && (numBytesRead == 0) + && (info->compressedSize > 0) + && (info->compressedSize != UTIL_FILESIZE_UNKNOWN) ) { unsigned long long file_position = (unsigned long long) LONG_TELL(srcFile); unsigned long long file_size = (unsigned long long) info->compressedSize; ERROR_IF(file_position != file_size, info_truncated_input, - "Error: seeked to position %llu, which is beyond file size of %llu\n", - file_position, - file_size); + "Error: seeked to position %llu, which is beyond file size of %llu\n", + file_position, + file_size); break; /* correct end of file => success */ } ERROR_IF(feof(srcFile), info_not_zstd, "Error: reached end of file with incomplete frame"); @@ -2762,19 +2731,19 @@ FIO_analyzeFrames(fileInfo_t* info, FILE* const srcFile) ZSTD_frameHeader header; U64 const frameContentSize = ZSTD_getFrameContentSize(headerBuffer, numBytesRead); if ( frameContentSize == ZSTD_CONTENTSIZE_ERROR - || frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN ) { + || frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN ) { info->decompUnavailable = 1; } else { info->decompressedSize += frameContentSize; } ERROR_IF(ZSTD_getFrameHeader(&header, headerBuffer, numBytesRead) != 0, - info_frame_error, "Error: could not decode frame header"); + info_frame_error, "Error: could not decode frame header"); info->windowSize = header.windowSize; /* move to the end of the frame header */ { size_t const headerSize = ZSTD_frameHeaderSize(headerBuffer, numBytesRead); ERROR_IF(ZSTD_isError(headerSize), info_frame_error, "Error: could not determine frame header size"); ERROR_IF(fseek(srcFile, ((long)headerSize)-((long)numBytesRead), SEEK_CUR) != 0, - info_frame_error, "Error: could not move to end of frame header"); + info_frame_error, "Error: could not move to end of frame header"); } /* skip all blocks in the frame */ @@ -2782,7 +2751,7 @@ FIO_analyzeFrames(fileInfo_t* info, FILE* const srcFile) do { BYTE blockHeaderBuffer[3]; ERROR_IF(fread(blockHeaderBuffer, 1, 3, srcFile) != 3, - info_frame_error, "Error while reading block header"); + info_frame_error, "Error while reading block header"); { U32 const blockHeader = MEM_readLE24(blockHeaderBuffer); U32 const blockTypeID = (blockHeader >> 1) & 3; U32 const isRLE = (blockTypeID == 1); @@ -2791,7 +2760,7 @@ FIO_analyzeFrames(fileInfo_t* info, FILE* const srcFile) ERROR_IF(isWrongBlock, info_frame_error, "Error: unsupported block type"); lastBlock = blockHeader & 1; ERROR_IF(fseek(srcFile, blockSize, SEEK_CUR) != 0, - info_frame_error, "Error: could not skip to end of block"); + info_frame_error, "Error: could not skip to end of block"); } } while (lastBlock != 1); } @@ -2802,19 +2771,19 @@ FIO_analyzeFrames(fileInfo_t* info, FILE* const srcFile) if (contentChecksumFlag) { info->usesCheck = 1; ERROR_IF(fseek(srcFile, 4, SEEK_CUR) != 0, - info_frame_error, "Error: could not skip past checksum"); - } } + info_frame_error, "Error: could not skip past checksum"); + } } info->numActualFrames++; } - /* Skippable frame */ + /* Skippable frame */ else if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { U32 const frameSize = MEM_readLE32(headerBuffer + 4); long const seek = (long)(8 + frameSize - numBytesRead); ERROR_IF(LONG_SEEK(srcFile, seek, SEEK_CUR) != 0, - info_frame_error, "Error: could not find end of skippable frame"); + info_frame_error, "Error: could not find end of skippable frame"); info->numSkippableFrames++; } - /* unknown content */ + /* unknown content */ else { return info_not_zstd; } @@ -2848,7 +2817,7 @@ static InfoError getFileInfo(fileInfo_t* info, const char* srcFileName) { ERROR_IF(!UTIL_isRegularFile(srcFileName), - info_file_error, "Error : %s is not a file", srcFileName); + info_file_error, "Error : %s is not a file", srcFileName); return getFileInfo_fileConfirmed(info, srcFileName); } @@ -2864,17 +2833,17 @@ displayInfo(const char* inFileName, const fileInfo_t* info, int displayLevel) if (displayLevel <= 2) { if (!info->decompUnavailable) { DISPLAYOUT("%6d %5d %6.*f%4s %8.*f%4s %5.3f %5s %s\n", - info->numSkippableFrames + info->numActualFrames, - info->numSkippableFrames, - compressed_hrs.precision, compressed_hrs.value, compressed_hrs.suffix, - decompressed_hrs.precision, decompressed_hrs.value, decompressed_hrs.suffix, - ratio, checkString, inFileName); + info->numSkippableFrames + info->numActualFrames, + info->numSkippableFrames, + compressed_hrs.precision, compressed_hrs.value, compressed_hrs.suffix, + decompressed_hrs.precision, decompressed_hrs.value, decompressed_hrs.suffix, + ratio, checkString, inFileName); } else { DISPLAYOUT("%6d %5d %6.*f%4s %5s %s\n", - info->numSkippableFrames + info->numActualFrames, - info->numSkippableFrames, - compressed_hrs.precision, compressed_hrs.value, compressed_hrs.suffix, - checkString, inFileName); + info->numSkippableFrames + info->numActualFrames, + info->numSkippableFrames, + compressed_hrs.precision, compressed_hrs.value, compressed_hrs.suffix, + checkString, inFileName); } } else { DISPLAYOUT("%s \n", inFileName); @@ -2885,12 +2854,12 @@ displayInfo(const char* inFileName, const fileInfo_t* info, int displayLevel) window_hrs.precision, window_hrs.value, window_hrs.suffix, (unsigned long long)info->windowSize); DISPLAYOUT("Compressed Size: %.*f%s (%llu B)\n", - compressed_hrs.precision, compressed_hrs.value, compressed_hrs.suffix, - (unsigned long long)info->compressedSize); + compressed_hrs.precision, compressed_hrs.value, compressed_hrs.suffix, + (unsigned long long)info->compressedSize); if (!info->decompUnavailable) { DISPLAYOUT("Decompressed Size: %.*f%s (%llu B)\n", - decompressed_hrs.precision, decompressed_hrs.value, decompressed_hrs.suffix, - (unsigned long long)info->decompressedSize); + decompressed_hrs.precision, decompressed_hrs.value, decompressed_hrs.suffix, + (unsigned long long)info->decompressedSize); DISPLAYOUT("Ratio: %.4f\n", ratio); } DISPLAYOUT("Check: %s\n", checkString); @@ -2921,7 +2890,7 @@ FIO_listFile(fileInfo_t* total, const char* inFileName, int displayLevel) switch (error) { case info_frame_error: /* display error, but provide output */ - DISPLAYLEVEL(1, "Error while parsing \"%s\" \n", inFileName); + DISPLAYLEVEL(1, "Error while parsing \"%s\" \n", inFileName); break; case info_not_zstd: DISPLAYOUT("File \"%s\" not compressed by zstd \n", inFileName); @@ -2953,8 +2922,8 @@ int FIO_listMultipleFiles(unsigned numFiles, const char** filenameTable, int dis { unsigned u; for (u=0; u 1 && displayLevel <= 2) { /* display total */ UTIL_HumanReadableSize_t const compressed_hrs = UTIL_makeHumanReadableSize(total.compressedSize); UTIL_HumanReadableSize_t const decompressed_hrs = UTIL_makeHumanReadableSize(total.decompressedSize); @@ -2984,18 +2953,18 @@ int FIO_listMultipleFiles(unsigned numFiles, const char** filenameTable, int dis DISPLAYOUT("----------------------------------------------------------------- \n"); if (total.decompUnavailable) { DISPLAYOUT("%6d %5d %6.*f%4s %5s %u files\n", - total.numSkippableFrames + total.numActualFrames, - total.numSkippableFrames, - compressed_hrs.precision, compressed_hrs.value, compressed_hrs.suffix, - checkString, (unsigned)total.nbFiles); + total.numSkippableFrames + total.numActualFrames, + total.numSkippableFrames, + compressed_hrs.precision, compressed_hrs.value, compressed_hrs.suffix, + checkString, (unsigned)total.nbFiles); } else { DISPLAYOUT("%6d %5d %6.*f%4s %8.*f%4s %5.3f %5s %u files\n", - total.numSkippableFrames + total.numActualFrames, - total.numSkippableFrames, - compressed_hrs.precision, compressed_hrs.value, compressed_hrs.suffix, - decompressed_hrs.precision, decompressed_hrs.value, decompressed_hrs.suffix, - ratio, checkString, (unsigned)total.nbFiles); - } } + total.numSkippableFrames + total.numActualFrames, + total.numSkippableFrames, + compressed_hrs.precision, compressed_hrs.value, compressed_hrs.suffix, + decompressed_hrs.precision, decompressed_hrs.value, decompressed_hrs.suffix, + ratio, checkString, (unsigned)total.nbFiles); + } } return error; } } diff --git a/programs/fileio_asyncio.c b/programs/fileio_asyncio.c index 868720a1da2..248baed6fba 100644 --- a/programs/fileio_asyncio.c +++ b/programs/fileio_asyncio.c @@ -29,7 +29,8 @@ /** AIO_fwriteSparse() : * @return : storedSkips, * argument for next call to AIO_fwriteSparse() or AIO_fwriteSparseEnd() */ -unsigned AIO_fwriteSparse(FILE* file, +static unsigned +AIO_fwriteSparse(FILE* file, const void* buffer, size_t bufferSize, const FIO_prefs_t* const prefs, unsigned storedSkips) @@ -106,7 +107,8 @@ unsigned AIO_fwriteSparse(FILE* file, return storedSkips; } -void AIO_fwriteSparseEnd(const FIO_prefs_t* const prefs, FILE* file, unsigned storedSkips) +static void +AIO_fwriteSparseEnd(const FIO_prefs_t* const prefs, FILE* file, unsigned storedSkips) { if (prefs->testMode) assert(storedSkips == 0); if (storedSkips>0) { @@ -363,3 +365,223 @@ void AIO_WritePool_free(WritePoolCtx_t* ctx) { assert(ctx->storedSkips==0); free(ctx); } + + +/* *********************************** + * ReadPool implementation + *************************************/ +static void ReadPool_releaseAllCompletedJobs(read_pool_ctx_t* ctx) { + int i; + for(i=0; icompletedJobsCount; i++) { + io_job_t* job = (io_job_t*) ctx->completedJobs[i]; + IoPool_releaseIoJob(job); + } + ctx->completedJobsCount = 0; +} + +static void ReadPool_addJobToCompleted(io_job_t *job) { + read_pool_ctx_t *ctx = (read_pool_ctx_t *)job->ctx; + if(ctx->base.threadPool) + ZSTD_pthread_mutex_lock(&ctx->base.ioJobsMutex); + assert(ctx->completedJobsCount < MAX_IO_JOBS); + ctx->completedJobs[ctx->completedJobsCount++] = job; + if(ctx->base.threadPool) { + ZSTD_pthread_cond_signal(&ctx->jobCompletedCond); + ZSTD_pthread_mutex_unlock(&ctx->base.ioJobsMutex); + } +} + +/* ReadPool_findNextWaitingOffsetCompletedJob: + * Looks through the completed jobs for a job matching the waitingOnOffset and returns it, + * if job wasn't found returns NULL. + * IMPORTANT: assumes ioJobsMutex is locked. */ +static io_job_t* ReadPool_findNextWaitingOffsetCompletedJob(read_pool_ctx_t *ctx) { + io_job_t *job = NULL; + int i; + for (i=0; icompletedJobsCount; i++) { + job = (io_job_t *) ctx->completedJobs[i]; + if (job->offset == ctx->waitingOnOffset) { + ctx->completedJobs[i] = ctx->completedJobs[--ctx->completedJobsCount]; + return job; + } + } + return NULL; +} + +/* ReadPool_getNextCompletedJob: + * Returns a completed io_job_t for the next read in line based on waitingOnOffset and advances waitingOnOffset. + * Would block. */ +static io_job_t* ReadPool_getNextCompletedJob(read_pool_ctx_t *ctx) { + io_job_t *job = NULL; + if(ctx->base.threadPool) + ZSTD_pthread_mutex_lock(&ctx->base.ioJobsMutex); + + job = ReadPool_findNextWaitingOffsetCompletedJob(ctx); + + /* As long as we didn't find the job matching the next read, and we have some reads in flight continue waiting */ + while (!job && (ctx->base.availableJobsCount + ctx->completedJobsCount < ctx->base.totalIoJobs)) { + assert(ctx->base.threadPool != NULL); /* we shouldn't be here if we work in sync mode */ + ZSTD_pthread_cond_wait(&ctx->jobCompletedCond, &ctx->base.ioJobsMutex); + job = ReadPool_findNextWaitingOffsetCompletedJob(ctx); + } + + if(job) { + assert(job->offset == ctx->waitingOnOffset); + ctx->waitingOnOffset += job->usedBufferSize; + } + + if(ctx->base.threadPool) + ZSTD_pthread_mutex_unlock(&ctx->base.ioJobsMutex); + return job; +} + + +/* ReadPool_executeReadJob: + * Executes a read job synchronously. Can be used as a function for a thread pool. */ +static void ReadPool_executeReadJob(void* opaque){ + io_job_t* job = (io_job_t*) opaque; + read_pool_ctx_t* ctx = (read_pool_ctx_t *)job->ctx; + if(ctx->reachedEof) { + job->usedBufferSize = 0; + ReadPool_addJobToCompleted(job); + return; + } + job->usedBufferSize = fread(job->buffer, 1, job->bufferSize, job->file); + if(job->usedBufferSize < job->bufferSize) { + if(ferror(job->file)) { + EXM_THROW(37, "Read error"); + } else if(feof(job->file)) { + ctx->reachedEof = 1; + } else + EXM_THROW(37, "Unexpected short read"); + } + ReadPool_addJobToCompleted(job); +} + +static void ReadPool_enqueueRead(read_pool_ctx_t *ctx) { + io_job_t *job = IoPool_acquireJob(&ctx->base); + job->offset = ctx->nextReadOffset; + ctx->nextReadOffset += job->bufferSize; + IoPool_enqueueJob(job); +} + +static void ReadPool_startReading(read_pool_ctx_t *ctx) { + int i; + for (i = 0; i < ctx->base.availableJobsCount; i++) { + ReadPool_enqueueRead(ctx); + } +} + +/* ReadPool_setFile: + * Sets the source file for future read in the pool. Initiates reading immediately if file is not NULL. + * Waits for all current enqueued tasks to complete if a previous file was set. */ +void ReadPool_setFile(read_pool_ctx_t *ctx, FILE* file) { + assert(ctx!=NULL); + IoPool_join(&ctx->base); + ReadPool_releaseAllCompletedJobs(ctx); + IoPool_setFile(&ctx->base, file); + ctx->nextReadOffset = 0; + ctx->waitingOnOffset = 0; + ctx->srcBuffer = ctx->srcBufferBase; + ctx->reachedEof = 0; + if(file != NULL) + ReadPool_startReading(ctx); +} + +/* ReadPool_create: + * Allocates and sets and a new readPool including its included jobs. + * bufferSize should be set to the maximal buffer we want to read at a time, will also be used + * as our basic read size. */ +read_pool_ctx_t* ReadPool_create(FIO_prefs_t* const prefs, size_t bufferSize) { + read_pool_ctx_t* ctx = (read_pool_ctx_t*) malloc(sizeof(read_pool_ctx_t)); + if(!ctx) EXM_THROW(100, "Allocation error : not enough memory"); + IoPool_init(&ctx->base, prefs, ReadPool_executeReadJob, bufferSize); + + ctx->srcBufferBaseSize = 2 * bufferSize; + ctx->srcBufferBase = (U8*) malloc(ctx->srcBufferBaseSize); + ctx->srcBuffer = ctx->srcBufferBase; + ctx->srcBufferLoaded = 0; + ctx->completedJobsCount = 0; + + if(ctx->base.threadPool) + if (ZSTD_pthread_cond_init(&ctx->jobCompletedCond, NULL)) + EXM_THROW(103,"Failed creating write jobCompletedCond mutex"); + + return ctx; +} + +/* ReadPool_free: + * Frees and releases a readPool and its resources. Closes source file. */ +void ReadPool_free(read_pool_ctx_t* ctx) { + if(ReadPool_getFile(ctx)) + ReadPool_closeFile(ctx); + if(ctx->base.threadPool) + ZSTD_pthread_cond_destroy(&ctx->jobCompletedCond); + IoPool_destroy(&ctx->base); + free(ctx->srcBufferBase); + free(ctx); +} + +/* ReadPool_consumeBytes: + * Consumes byes from srcBuffer's beginning and updates srcBufferLoaded accordingly. */ +void ReadPool_consumeBytes(read_pool_ctx_t *ctx, size_t n) { + assert(n <= ctx->srcBufferLoaded); + assert(ctx->srcBuffer + n <= ctx->srcBufferBase + ctx->srcBufferBaseSize); + ctx->srcBufferLoaded -= n; + ctx->srcBuffer += n; +} + +/* ReadPool_fillBuffer: + * Makes sure buffer has at least n bytes loaded (as long as n is not bigger than the initalized bufferSize). + * Returns if srcBuffer has at least n bytes loaded or if we've reached the end of the file. + * Return value is the number of bytes added to the buffer. + * Note that srcBuffer might have up to 2 times bufferSize bytes. */ +size_t ReadPool_fillBuffer(read_pool_ctx_t *ctx, size_t n) { + io_job_t *job; + size_t srcBufferOffsetFromBase; + size_t srcBufferRemainingSpace; + size_t bytesRead = 0; + assert(n <= ctx->srcBufferBaseSize/2); + while (ctx->srcBufferLoaded < n) { + job = ReadPool_getNextCompletedJob(ctx); + if(job == NULL) + break; + srcBufferOffsetFromBase = ctx->srcBuffer - ctx->srcBufferBase; + srcBufferRemainingSpace = ctx->srcBufferBaseSize - (srcBufferOffsetFromBase + ctx->srcBufferLoaded); + if(job->usedBufferSize > srcBufferRemainingSpace) { + memmove(ctx->srcBufferBase, ctx->srcBuffer, ctx->srcBufferLoaded); + ctx->srcBuffer = ctx->srcBufferBase; + } + memcpy(ctx->srcBuffer + ctx->srcBufferLoaded, job->buffer, job->usedBufferSize); + bytesRead += job->usedBufferSize; + ctx->srcBufferLoaded += job->usedBufferSize; + if(job->usedBufferSize < job->bufferSize) { + IoPool_releaseIoJob(job); + break; + } + IoPool_releaseIoJob(job); + ReadPool_enqueueRead(ctx); + } + return bytesRead; +} + +/* ReadPool_consumeAndRefill: + * Consumes the current buffer and refills it with bufferSize bytes. */ +size_t ReadPool_consumeAndRefill(read_pool_ctx_t *ctx) { + ReadPool_consumeBytes(ctx, ctx->srcBufferLoaded); + return ReadPool_fillBuffer(ctx, ctx->srcBufferBaseSize/2); +} + +/* ReadPool_getFile: + * Returns the current file set for the read pool. */ +FILE* ReadPool_getFile(read_pool_ctx_t *ctx) { + return IoPool_getFile(&ctx->base); +} + +/* ReadPool_closeFile: + * Closes the current set file. Waits for all current enqueued tasks to complete and resets state. */ +int ReadPool_closeFile(read_pool_ctx_t *ctx) { + FILE* file = ReadPool_getFile(ctx); + ReadPool_setFile(ctx, NULL); + return fclose(file); +} diff --git a/programs/fileio_asyncio.h b/programs/fileio_asyncio.h index 3e91164c558..0522b575bb2 100644 --- a/programs/fileio_asyncio.h +++ b/programs/fileio_asyncio.h @@ -41,6 +41,30 @@ typedef struct { int availableJobsCount; } IOPoolCtx_t; +typedef struct { + io_pool_ctx_t base; + + /* State regarding the currently read file */ + int reachedEof; + U64 nextReadOffset; + U64 waitingOnOffset; + + /* Bases buffer, shouldn't be accessed from outside ot utility functions. */ + U8 *srcBufferBase; + size_t srcBufferBaseSize; + + /* Read buffer can be used by consumer code, take care when copying this pointer aside as it might + * change when consuming / refilling buffer. */ + U8 *srcBuffer; + size_t srcBufferLoaded; + + /* We need to know what tasks completed so we can use their buffers when their time comes. + * Should only be accessed after locking base.ioJobsMutex . */ + void* completedJobs[MAX_IO_JOBS]; + int completedJobsCount; + ZSTD_pthread_cond_t jobCompletedCond; +} read_pool_ctx_t; + typedef struct { IOPoolCtx_t base; unsigned storedSkips; @@ -59,15 +83,6 @@ typedef struct { U64 offset; } IOJob_t; -/** AIO_fwriteSparse() : -* @return : storedSkips, -* argument for next call to AIO_fwriteSparse() or AIO_fwriteSparseEnd() */ -unsigned AIO_fwriteSparse(FILE* file, - const void* buffer, size_t bufferSize, - const FIO_prefs_t* const prefs, - unsigned storedSkips); - -void AIO_fwriteSparseEnd(const FIO_prefs_t* const prefs, FILE* file, unsigned storedSkips); /* AIO_WritePool_releaseIoJob: * Releases an acquired job back to the pool. Doesn't execute the job. */ @@ -113,6 +128,44 @@ WritePoolCtx_t* AIO_WritePool_create(FIO_prefs_t* const prefs, size_t bufferSize * Frees and releases a writePool and its resources. Closes destination file. */ void AIO_WritePool_free(WritePoolCtx_t* ctx); +/* ReadPool_create: + * Allocates and sets and a new readPool including its included jobs. + * bufferSize should be set to the maximal buffer we want to read at a time, will also be used + * as our basic read size. */ +read_pool_ctx_t* ReadPool_create(FIO_prefs_t* const prefs, size_t bufferSize); + +/* ReadPool_free: + * Frees and releases a readPool and its resources. Closes source file. */ +void ReadPool_free(read_pool_ctx_t* ctx); + +/* ReadPool_consumeBytes: + * Consumes byes from srcBuffer's beginning and updates srcBufferLoaded accordingly. */ +void ReadPool_consumeBytes(read_pool_ctx_t *ctx, size_t n); + +/* ReadPool_fillBuffer: + * Makes sure buffer has at least n bytes loaded (as long as n is not bigger than the initalized bufferSize). + * Returns if srcBuffer has at least n bytes loaded or if we've reached the end of the file. + * Return value is the number of bytes added to the buffer. + * Note that srcBuffer might have up to 2 times bufferSize bytes. */ +size_t ReadPool_fillBuffer(read_pool_ctx_t *ctx, size_t n); + +/* ReadPool_consumeAndRefill: + * Consumes the current buffer and refills it with bufferSize bytes. */ +size_t ReadPool_consumeAndRefill(read_pool_ctx_t *ctx); + +/* ReadPool_setFile: + * Sets the source file for future read in the pool. Initiates reading immediately if file is not NULL. + * Waits for all current enqueued tasks to complete if a previous file was set. */ +void ReadPool_setFile(read_pool_ctx_t *ctx, FILE* file); + +/* ReadPool_getFile: + * Returns the current file set for the read pool. */ +FILE* ReadPool_getFile(read_pool_ctx_t *ctx); + +/* ReadPool_closeFile: + * Closes the current set file. Waits for all current enqueued tasks to complete and resets state. */ +int ReadPool_closeFile(read_pool_ctx_t *ctx); + #if defined (__cplusplus) } #endif diff --git a/programs/fileio_types.h b/programs/fileio_types.h index 1909ab1ab5a..7366d77240c 100644 --- a/programs/fileio_types.h +++ b/programs/fileio_types.h @@ -70,4 +70,4 @@ typedef struct FIO_prefs_s { int allowBlockDevices; } FIO_prefs_t; -#endif /* FILEIO_TYPES_HEADER */ \ No newline at end of file +#endif /* FILEIO_TYPES_HEADER */ diff --git a/tests/playTests.sh b/tests/playTests.sh index 78d8e742aa3..b795823d782 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -185,7 +185,7 @@ fi println "\n===> simple tests " -datagen > tmp +datagen -g500K > tmp zstd -h zstd -H zstd -V @@ -1575,7 +1575,7 @@ elif [ "$longCSize19wlog23" -gt "$optCSize19wlog23" ]; then exit 1 fi -println "\n===> zstd asyncio decompression tests " +println "\n===> zstd asyncio tests " addFrame() { datagen -g2M -s$2 >> tmp_uncompressed From 4ef1dddc08d4b33a024b56e8a7ab48472f364b27 Mon Sep 17 00:00:00 2001 From: Yonatan Komornik Date: Mon, 24 Jan 2022 14:11:41 -0800 Subject: [PATCH 06/23] CR fixes (naming conventions) --- programs/fileio.c | 60 +++++++++++++++++++-------------------- programs/fileio_asyncio.c | 40 +++++++++++++------------- programs/fileio_asyncio.h | 2 +- 3 files changed, 51 insertions(+), 51 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index 4bf29d870a6..9c5a3b15387 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -818,7 +818,7 @@ typedef struct { size_t dictBufferSize; const char* dictFileName; ZSTD_CStream* cctx; - write_pool_ctx_t *writeCtx; + WritePoolCtx_t *writeCtx; read_pool_ctx_t *readCtx; } cRess_t; @@ -877,7 +877,7 @@ static cRess_t FIO_createCResources(FIO_prefs_t* const prefs, } ress.dictBufferSize = FIO_createDictBuffer(&ress.dictBuffer, dictFileName, prefs); /* works with dictFileName==NULL */ - ress.writeCtx = WritePool_create(prefs, ZSTD_CStreamOutSize()); + ress.writeCtx = AIO_WritePool_create(prefs, ZSTD_CStreamOutSize()); ress.readCtx = ReadPool_create(prefs, ZSTD_CStreamInSize()); /* Advanced parameters, including dictionary */ @@ -942,7 +942,7 @@ static cRess_t FIO_createCResources(FIO_prefs_t* const prefs, static void FIO_freeCResources(const cRess_t* const ress) { free(ress->dictBuffer); - WritePool_free(ress->writeCtx); + AIO_WritePool_free(ress->writeCtx); ReadPool_free(ress->readCtx); ZSTD_freeCStream(ress->cctx); /* never fails */ } @@ -956,7 +956,7 @@ FIO_compressGzFrame(const cRess_t* ress, /* buffers & handlers are used, but no { unsigned long long inFileSize = 0, outFileSize = 0; z_stream strm; - io_job_t *writeJob = NULL; + IOJob_t *writeJob = NULL; if (compressionLevel > Z_BEST_COMPRESSION) compressionLevel = Z_BEST_COMPRESSION; @@ -972,7 +972,7 @@ FIO_compressGzFrame(const cRess_t* ress, /* buffers & handlers are used, but no EXM_THROW(71, "zstd: %s: deflateInit2 error %d \n", srcFileName, ret); } } - writeJob = WritePool_acquireJob(ress->writeCtx); + writeJob = AIO_WritePool_acquireJob(ress->writeCtx); strm.next_in = 0; strm.avail_in = 0; strm.next_out = (Bytef*)writeJob->buffer; @@ -999,7 +999,7 @@ FIO_compressGzFrame(const cRess_t* ress, /* buffers & handlers are used, but no { size_t const cSize = writeJob->bufferSize - strm.avail_out; if (cSize) { writeJob->usedBufferSize = cSize; - WritePool_enqueueAndReacquireWriteJob(&writeJob); + AIO_WritePool_enqueueAndReacquireWriteJob(&writeJob); outFileSize += cSize; strm.next_out = (Bytef*)writeJob->buffer; strm.avail_out = (uInt)writeJob->bufferSize; @@ -1019,7 +1019,7 @@ FIO_compressGzFrame(const cRess_t* ress, /* buffers & handlers are used, but no { size_t const cSize = writeJob->bufferSize - strm.avail_out; if (cSize) { writeJob->usedBufferSize = cSize; - WritePool_enqueueAndReacquireWriteJob(&writeJob); + AIO_WritePool_enqueueAndReacquireWriteJob(&writeJob); outFileSize += cSize; strm.next_out = (Bytef*)writeJob->buffer; strm.avail_out = (uInt)writeJob->bufferSize; @@ -1034,8 +1034,8 @@ FIO_compressGzFrame(const cRess_t* ress, /* buffers & handlers are used, but no EXM_THROW(79, "zstd: %s: deflateEnd error %d \n", srcFileName, ret); } } *readsize = inFileSize; - WritePool_releaseIoJob(writeJob); - WritePool_sparseWriteEnd(ress->writeCtx); + AIO_WritePool_releaseIoJob(writeJob); + AIO_WritePool_sparseWriteEnd(ress->writeCtx); return outFileSize; } #endif @@ -1051,7 +1051,7 @@ FIO_compressLzmaFrame(cRess_t* ress, lzma_stream strm = LZMA_STREAM_INIT; lzma_action action = LZMA_RUN; lzma_ret ret; - io_job_t *writeJob = NULL; + IOJob_t *writeJob = NULL; if (compressionLevel < 0) compressionLevel = 0; if (compressionLevel > 9) compressionLevel = 9; @@ -1069,7 +1069,7 @@ FIO_compressLzmaFrame(cRess_t* ress, EXM_THROW(83, "zstd: %s: lzma_easy_encoder error %d", srcFileName, ret); } - writeJob = WritePool_acquireJob(ress->writeCtx); + writeJob =AIO_WritePool_acquireJob(ress->writeCtx); strm.next_out = (Bytef*)writeJob->buffer; strm.avail_out = (uInt)writeJob->bufferSize; strm.next_in = 0; @@ -1096,7 +1096,7 @@ FIO_compressLzmaFrame(cRess_t* ress, { size_t const compBytes = writeJob->bufferSize - strm.avail_out; if (compBytes) { writeJob->usedBufferSize = compBytes; - WritePool_enqueueAndReacquireWriteJob(&writeJob); + AIO_WritePool_enqueueAndReacquireWriteJob(&writeJob); outFileSize += compBytes; strm.next_out = (Bytef*)writeJob->buffer; strm.avail_out = writeJob->bufferSize; @@ -1115,8 +1115,8 @@ FIO_compressLzmaFrame(cRess_t* ress, lzma_end(&strm); *readsize = inFileSize; - WritePool_releaseIoJob(writeJob); - WritePool_sparseWriteEnd(ress->writeCtx); + AIO_WritePool_releaseIoJob(writeJob); + AIO_WritePool_sparseWriteEnd(ress->writeCtx); return outFileSize; } @@ -1143,7 +1143,7 @@ FIO_compressLz4Frame(cRess_t* ress, LZ4F_preferences_t prefs; LZ4F_compressionContext_t ctx; - io_job_t *writeJob = WritePool_acquireJob(ress->writeCtx); + IOJob_t *writeJob =AIO_WritePool_acquireJob(ress->writeCtx); LZ4F_errorCode_t const errorCode = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION); if (LZ4F_isError(errorCode)) @@ -1170,7 +1170,7 @@ FIO_compressLz4Frame(cRess_t* ress, EXM_THROW(33, "File header generation failed : %s", LZ4F_getErrorName(headerSize)); writeJob->usedBufferSize = headerSize; - WritePool_enqueueAndReacquireWriteJob(&writeJob); + AIO_WritePool_enqueueAndReacquireWriteJob(&writeJob); outFileSize += headerSize; /* Read first block */ @@ -1197,7 +1197,7 @@ FIO_compressLz4Frame(cRess_t* ress, /* Write Block */ writeJob->usedBufferSize = outSize; - WritePool_enqueueAndReacquireWriteJob(&writeJob); + AIO_WritePool_enqueueAndReacquireWriteJob(&writeJob); /* Read next block */ ReadPool_consumeBytes(ress->readCtx, ress->readCtx->srcBufferLoaded); @@ -1212,14 +1212,14 @@ FIO_compressLz4Frame(cRess_t* ress, srcFileName, LZ4F_getErrorName(headerSize)); writeJob->usedBufferSize = headerSize; - WritePool_enqueueAndReacquireWriteJob(&writeJob); + AIO_WritePool_enqueueAndReacquireWriteJob(&writeJob); outFileSize += headerSize; } *readsize = inFileSize; LZ4F_freeCompressionContext(ctx); - WritePool_releaseIoJob(writeJob); - WritePool_sparseWriteEnd(ress->writeCtx); + AIO_WritePool_releaseIoJob(writeJob); + AIO_WritePool_sparseWriteEnd(ress->writeCtx); return outFileSize; } @@ -1234,7 +1234,7 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, int compressionLevel, U64* readsize) { cRess_t const ress = *ressPtr; - io_job_t *writeJob = WritePool_acquireJob(ressPtr->writeCtx); + IOJob_t *writeJob =AIO_WritePool_acquireJob(ressPtr->writeCtx); U64 compressedfilesize = 0; ZSTD_EndDirective directive = ZSTD_e_continue; @@ -1308,7 +1308,7 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, (unsigned)directive, (unsigned)inBuff.pos, (unsigned)inBuff.size, (unsigned)outBuff.pos); if (outBuff.pos) { writeJob->usedBufferSize = outBuff.pos; - WritePool_enqueueAndReacquireWriteJob(&writeJob); + AIO_WritePool_enqueueAndReacquireWriteJob(&writeJob); compressedfilesize += outBuff.pos; } @@ -1445,8 +1445,8 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, (unsigned long long)*readsize, (unsigned long long)fileSize); } - WritePool_releaseIoJob(writeJob); - WritePool_sparseWriteEnd(ressPtr->writeCtx); + AIO_WritePool_releaseIoJob(writeJob); + AIO_WritePool_sparseWriteEnd(ressPtr->writeCtx); return compressedfilesize; } @@ -1569,7 +1569,7 @@ static int FIO_compressFilename_dstFile(FIO_ctx_t* const fCtx, int transferMTime = 0; FILE *dstFile; assert(ReadPool_getFile(ress.readCtx) != NULL); - if (WritePool_getFile(ress.writeCtx) == NULL) { + if (AIO_WritePool_getFile(ress.writeCtx) == NULL) { int dstFilePermissions = DEFAULT_FILE_PERMISSIONS; if ( strcmp (srcFileName, stdinmark) && strcmp (dstFileName, stdoutmark) @@ -1583,7 +1583,7 @@ static int FIO_compressFilename_dstFile(FIO_ctx_t* const fCtx, DISPLAYLEVEL(6, "FIO_compressFilename_dstFile: opening dst: %s \n", dstFileName); dstFile = FIO_openDstFile(fCtx, prefs, srcFileName, dstFileName, dstFilePermissions); if (dstFile==NULL) return 1; /* could not open dstFileName */ - WritePool_setFile(ress.writeCtx, dstFile); + AIO_WritePool_setFile(ress.writeCtx, dstFile); /* Must only be added after FIO_openDstFile() succeeds. * Otherwise we may delete the destination file if it already exists, * and the user presses Ctrl-C when asked if they wish to overwrite. @@ -1597,7 +1597,7 @@ static int FIO_compressFilename_dstFile(FIO_ctx_t* const fCtx, clearHandler(); DISPLAYLEVEL(6, "FIO_compressFilename_dstFile: closing dst: %s \n", dstFileName); - if (WritePool_closeFile(ress.writeCtx)) { /* error closing file */ + if (AIO_WritePool_closeFile(ress.writeCtx)) { /* error closing file */ DISPLAYLEVEL(1, "zstd: %s: %s \n", dstFileName, strerror(errno)); result=1; } @@ -1829,13 +1829,13 @@ int FIO_compressMultipleFilenames(FIO_ctx_t* const fCtx, if (dstFile == NULL) { /* could not open outFileName */ error = 1; } else { - WritePool_setFile(ress.writeCtx, dstFile); + AIO_WritePool_setFile(ress.writeCtx, dstFile); for (; fCtx->currFileIdx < fCtx->nbFilesTotal; ++fCtx->currFileIdx) { status = FIO_compressFilename_srcFile(fCtx, prefs, ress, outFileName, inFileNamesTable[fCtx->currFileIdx], compressionLevel); if (!status) fCtx->nbFilesProcessed++; error |= status; } - if (WritePool_closeFile(ress.writeCtx)) + if (AIO_WritePool_closeFile(ress.writeCtx)) EXM_THROW(29, "Write error (%s) : cannot properly close %s", strerror(errno), outFileName); } @@ -2059,7 +2059,7 @@ FIO_decompressZstdFrame(FIO_ctx_t* const fCtx, dRess_t* ress, if (readSize==0) { DISPLAYLEVEL(1, "%s : Read error (39) : premature end \n", srcFileName); - WritePool_releaseIoJob(writeJob); + AIO_WritePool_releaseIoJob(writeJob); return FIO_ERROR_FRAME_DECODING; } } } } diff --git a/programs/fileio_asyncio.c b/programs/fileio_asyncio.c index 248baed6fba..3bca60a0820 100644 --- a/programs/fileio_asyncio.c +++ b/programs/fileio_asyncio.c @@ -373,13 +373,13 @@ void AIO_WritePool_free(WritePoolCtx_t* ctx) { static void ReadPool_releaseAllCompletedJobs(read_pool_ctx_t* ctx) { int i; for(i=0; icompletedJobsCount; i++) { - io_job_t* job = (io_job_t*) ctx->completedJobs[i]; - IoPool_releaseIoJob(job); + IOJob_t* job = (IOJob_t*) ctx->completedJobs[i]; + AIO_IOPool_releaseIoJob(job); } ctx->completedJobsCount = 0; } -static void ReadPool_addJobToCompleted(io_job_t *job) { +static void ReadPool_addJobToCompleted(IOJob_t *job) { read_pool_ctx_t *ctx = (read_pool_ctx_t *)job->ctx; if(ctx->base.threadPool) ZSTD_pthread_mutex_lock(&ctx->base.ioJobsMutex); @@ -395,11 +395,11 @@ static void ReadPool_addJobToCompleted(io_job_t *job) { * Looks through the completed jobs for a job matching the waitingOnOffset and returns it, * if job wasn't found returns NULL. * IMPORTANT: assumes ioJobsMutex is locked. */ -static io_job_t* ReadPool_findNextWaitingOffsetCompletedJob(read_pool_ctx_t *ctx) { - io_job_t *job = NULL; +static IOJob_t* ReadPool_findNextWaitingOffsetCompletedJob(read_pool_ctx_t *ctx) { + IOJob_t *job = NULL; int i; for (i=0; icompletedJobsCount; i++) { - job = (io_job_t *) ctx->completedJobs[i]; + job = (IOJob_t *) ctx->completedJobs[i]; if (job->offset == ctx->waitingOnOffset) { ctx->completedJobs[i] = ctx->completedJobs[--ctx->completedJobsCount]; return job; @@ -409,10 +409,10 @@ static io_job_t* ReadPool_findNextWaitingOffsetCompletedJob(read_pool_ctx_t *ctx } /* ReadPool_getNextCompletedJob: - * Returns a completed io_job_t for the next read in line based on waitingOnOffset and advances waitingOnOffset. + * Returns a completed IOJob_t for the next read in line based on waitingOnOffset and advances waitingOnOffset. * Would block. */ -static io_job_t* ReadPool_getNextCompletedJob(read_pool_ctx_t *ctx) { - io_job_t *job = NULL; +static IOJob_t* ReadPool_getNextCompletedJob(read_pool_ctx_t *ctx) { + IOJob_t *job = NULL; if(ctx->base.threadPool) ZSTD_pthread_mutex_lock(&ctx->base.ioJobsMutex); @@ -439,7 +439,7 @@ static io_job_t* ReadPool_getNextCompletedJob(read_pool_ctx_t *ctx) { /* ReadPool_executeReadJob: * Executes a read job synchronously. Can be used as a function for a thread pool. */ static void ReadPool_executeReadJob(void* opaque){ - io_job_t* job = (io_job_t*) opaque; + IOJob_t* job = (IOJob_t*) opaque; read_pool_ctx_t* ctx = (read_pool_ctx_t *)job->ctx; if(ctx->reachedEof) { job->usedBufferSize = 0; @@ -459,10 +459,10 @@ static void ReadPool_executeReadJob(void* opaque){ } static void ReadPool_enqueueRead(read_pool_ctx_t *ctx) { - io_job_t *job = IoPool_acquireJob(&ctx->base); + IOJob_t *job = AIO_IOPool_acquireJob(&ctx->base); job->offset = ctx->nextReadOffset; ctx->nextReadOffset += job->bufferSize; - IoPool_enqueueJob(job); + AIO_IOPool_enqueueJob(job); } static void ReadPool_startReading(read_pool_ctx_t *ctx) { @@ -477,9 +477,9 @@ static void ReadPool_startReading(read_pool_ctx_t *ctx) { * Waits for all current enqueued tasks to complete if a previous file was set. */ void ReadPool_setFile(read_pool_ctx_t *ctx, FILE* file) { assert(ctx!=NULL); - IoPool_join(&ctx->base); + AIO_IOPool_join(&ctx->base); ReadPool_releaseAllCompletedJobs(ctx); - IoPool_setFile(&ctx->base, file); + AIO_IOPool_setFile(&ctx->base, file); ctx->nextReadOffset = 0; ctx->waitingOnOffset = 0; ctx->srcBuffer = ctx->srcBufferBase; @@ -495,7 +495,7 @@ void ReadPool_setFile(read_pool_ctx_t *ctx, FILE* file) { read_pool_ctx_t* ReadPool_create(FIO_prefs_t* const prefs, size_t bufferSize) { read_pool_ctx_t* ctx = (read_pool_ctx_t*) malloc(sizeof(read_pool_ctx_t)); if(!ctx) EXM_THROW(100, "Allocation error : not enough memory"); - IoPool_init(&ctx->base, prefs, ReadPool_executeReadJob, bufferSize); + AIO_IOPool_init(&ctx->base, prefs, ReadPool_executeReadJob, bufferSize); ctx->srcBufferBaseSize = 2 * bufferSize; ctx->srcBufferBase = (U8*) malloc(ctx->srcBufferBaseSize); @@ -517,7 +517,7 @@ void ReadPool_free(read_pool_ctx_t* ctx) { ReadPool_closeFile(ctx); if(ctx->base.threadPool) ZSTD_pthread_cond_destroy(&ctx->jobCompletedCond); - IoPool_destroy(&ctx->base); + AIO_IOPool_destroy(&ctx->base); free(ctx->srcBufferBase); free(ctx); } @@ -537,7 +537,7 @@ void ReadPool_consumeBytes(read_pool_ctx_t *ctx, size_t n) { * Return value is the number of bytes added to the buffer. * Note that srcBuffer might have up to 2 times bufferSize bytes. */ size_t ReadPool_fillBuffer(read_pool_ctx_t *ctx, size_t n) { - io_job_t *job; + IOJob_t *job; size_t srcBufferOffsetFromBase; size_t srcBufferRemainingSpace; size_t bytesRead = 0; @@ -556,10 +556,10 @@ size_t ReadPool_fillBuffer(read_pool_ctx_t *ctx, size_t n) { bytesRead += job->usedBufferSize; ctx->srcBufferLoaded += job->usedBufferSize; if(job->usedBufferSize < job->bufferSize) { - IoPool_releaseIoJob(job); + AIO_IOPool_releaseIoJob(job); break; } - IoPool_releaseIoJob(job); + AIO_IOPool_releaseIoJob(job); ReadPool_enqueueRead(ctx); } return bytesRead; @@ -575,7 +575,7 @@ size_t ReadPool_consumeAndRefill(read_pool_ctx_t *ctx) { /* ReadPool_getFile: * Returns the current file set for the read pool. */ FILE* ReadPool_getFile(read_pool_ctx_t *ctx) { - return IoPool_getFile(&ctx->base); + return AIO_IOPool_getFile(&ctx->base); } /* ReadPool_closeFile: diff --git a/programs/fileio_asyncio.h b/programs/fileio_asyncio.h index 0522b575bb2..77670624470 100644 --- a/programs/fileio_asyncio.h +++ b/programs/fileio_asyncio.h @@ -42,7 +42,7 @@ typedef struct { } IOPoolCtx_t; typedef struct { - io_pool_ctx_t base; + IOPoolCtx_t base; /* State regarding the currently read file */ int reachedEof; From 22552802a19e776c0476fdb7bb3f8716c4c21893 Mon Sep 17 00:00:00 2001 From: Yonatan Komornik Date: Fri, 21 Jan 2022 16:46:00 -0800 Subject: [PATCH 07/23] Reverted whitespace changes --- programs/fileio.c | 338 +++++++++++++++++++++++----------------------- 1 file changed, 169 insertions(+), 169 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index 9c5a3b15387..ec5fa49431f 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -832,20 +832,20 @@ static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat) } static void FIO_adjustParamsForPatchFromMode(FIO_prefs_t* const prefs, - ZSTD_compressionParameters* comprParams, - unsigned long long const dictSize, - unsigned long long const maxSrcFileSize, - int cLevel) + ZSTD_compressionParameters* comprParams, + unsigned long long const dictSize, + unsigned long long const maxSrcFileSize, + int cLevel) { unsigned const fileWindowLog = FIO_highbit64(maxSrcFileSize) + 1; ZSTD_compressionParameters const cParams = ZSTD_getCParams(cLevel, (size_t)maxSrcFileSize, (size_t)dictSize); FIO_adjustMemLimitForPatchFromMode(prefs, dictSize, maxSrcFileSize); if (fileWindowLog > ZSTD_WINDOWLOG_MAX) - DISPLAYLEVEL(1, "Max window log exceeded by file (compression ratio will suffer)\n"); + DISPLAYLEVEL(1, "Max window log exceeded by file (compression ratio will suffer)\n"); comprParams->windowLog = MAX(ZSTD_WINDOWLOG_MIN, MIN(ZSTD_WINDOWLOG_MAX, fileWindowLog)); if (fileWindowLog > ZSTD_cycleLog(cParams.chainLog, cParams.strategy)) { if (!prefs->ldmFlag) - DISPLAYLEVEL(1, "long mode automatically triggered\n"); + DISPLAYLEVEL(1, "long mode automatically triggered\n"); FIO_setLdmFlag(prefs, 1); } if (cParams.strategy >= ZSTD_btopt) { @@ -866,8 +866,8 @@ static cRess_t FIO_createCResources(FIO_prefs_t* const prefs, DISPLAYLEVEL(6, "FIO_createCResources \n"); ress.cctx = ZSTD_createCCtx(); if (ress.cctx == NULL) - EXM_THROW(30, "allocation error (%s): can't create ZSTD_CCtx", - strerror(errno)); + EXM_THROW(30, "allocation error (%s): can't create ZSTD_CCtx", + strerror(errno)); /* need to update memLimit before calling createDictBuffer * because of memLimit check inside it */ @@ -882,7 +882,7 @@ static cRess_t FIO_createCResources(FIO_prefs_t* const prefs, /* Advanced parameters, including dictionary */ if (dictFileName && (ress.dictBuffer==NULL)) - EXM_THROW(32, "allocation error : can't create dictBuffer"); + EXM_THROW(32, "allocation error : can't create dictBuffer"); ress.dictFileName = dictFileName; if (prefs->adaptiveMode && !prefs->ldmFlag && !comprParams.windowLog) @@ -966,11 +966,11 @@ FIO_compressGzFrame(const cRess_t* ress, /* buffers & handlers are used, but no strm.opaque = Z_NULL; { int const ret = deflateInit2(&strm, compressionLevel, Z_DEFLATED, - 15 /* maxWindowLogSize */ + 16 /* gzip only */, - 8, Z_DEFAULT_STRATEGY); /* see http://www.zlib.net/manual.html */ + 15 /* maxWindowLogSize */ + 16 /* gzip only */, + 8, Z_DEFAULT_STRATEGY); /* see http://www.zlib.net/manual.html */ if (ret != Z_OK) { EXM_THROW(71, "zstd: %s: deflateInit2 error %d \n", srcFileName, ret); - } } + } } writeJob = AIO_WritePool_acquireJob(ress->writeCtx); strm.next_in = 0; @@ -1026,13 +1026,13 @@ FIO_compressGzFrame(const cRess_t* ress, /* buffers & handlers are used, but no } } if (ret == Z_STREAM_END) break; if (ret != Z_BUF_ERROR) - EXM_THROW(77, "zstd: %s: deflate error %d \n", srcFileName, ret); + EXM_THROW(77, "zstd: %s: deflate error %d \n", srcFileName, ret); } { int const ret = deflateEnd(&strm); if (ret != Z_OK) { EXM_THROW(79, "zstd: %s: deflateEnd error %d \n", srcFileName, ret); - } } + } } *readsize = inFileSize; AIO_WritePool_releaseIoJob(writeJob); AIO_WritePool_sparseWriteEnd(ress->writeCtx); @@ -1258,9 +1258,9 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, pledgedSrcSize = fileSize; CHECK(ZSTD_CCtx_setPledgedSrcSize(ress.cctx, fileSize)); } else if (prefs->streamSrcSize > 0) { - /* unknown source size; use the declared stream size */ - pledgedSrcSize = prefs->streamSrcSize; - CHECK( ZSTD_CCtx_setPledgedSrcSize(ress.cctx, prefs->streamSrcSize) ); + /* unknown source size; use the declared stream size */ + pledgedSrcSize = prefs->streamSrcSize; + CHECK( ZSTD_CCtx_setPledgedSrcSize(ress.cctx, prefs->streamSrcSize) ); } { @@ -1290,7 +1290,7 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, stillToFlush = 1; while ((inBuff.pos != inBuff.size) /* input buffer must be entirely ingested */ - || (directive == ZSTD_e_end && stillToFlush != 0) ) { + || (directive == ZSTD_e_end && stillToFlush != 0) ) { size_t const oldIPos = inBuff.pos; ZSTD_outBuffer outBuff= { writeJob->buffer, writeJob->bufferSize, 0 }; @@ -1323,11 +1323,11 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, /* display progress notifications */ if (g_display_prefs.displayLevel >= 3) { DISPLAYUPDATE(3, "\r(L%i) Buffered :%6.*f%4s - Consumed :%6.*f%4s - Compressed :%6.*f%4s => %.2f%% ", - compressionLevel, - buffered_hrs.precision, buffered_hrs.value, buffered_hrs.suffix, - consumed_hrs.precision, consumed_hrs.value, consumed_hrs.suffix, - produced_hrs.precision, produced_hrs.value, produced_hrs.suffix, - cShare ); + compressionLevel, + buffered_hrs.precision, buffered_hrs.value, buffered_hrs.suffix, + consumed_hrs.precision, consumed_hrs.value, consumed_hrs.suffix, + produced_hrs.precision, produced_hrs.value, produced_hrs.suffix, + cShare ); } else if (g_display_prefs.displayLevel >= 2 || g_display_prefs.progressSetting == FIO_ps_always) { /* Require level 2 or forcibly displayed progress counter for summarized updates */ DISPLAYLEVEL(1, "\r%79s\r", ""); /* Clear out the current displayed line */ @@ -1337,15 +1337,15 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, if (srcFileNameSize > 18) { const char* truncatedSrcFileName = srcFileName + srcFileNameSize - 15; DISPLAYLEVEL(1, "Compress: %u/%u files. Current: ...%s ", - fCtx->currFileIdx+1, fCtx->nbFilesTotal, truncatedSrcFileName); + fCtx->currFileIdx+1, fCtx->nbFilesTotal, truncatedSrcFileName); } else { DISPLAYLEVEL(1, "Compress: %u/%u files. Current: %*s ", - fCtx->currFileIdx+1, fCtx->nbFilesTotal, (int)(18-srcFileNameSize), srcFileName); + fCtx->currFileIdx+1, fCtx->nbFilesTotal, (int)(18-srcFileNameSize), srcFileName); } } DISPLAYLEVEL(1, "Read:%6.*f%4s ", consumed_hrs.precision, consumed_hrs.value, consumed_hrs.suffix); if (fileSize != UTIL_FILESIZE_UNKNOWN) - DISPLAYLEVEL(2, "/%6.*f%4s", file_hrs.precision, file_hrs.value, file_hrs.suffix); + DISPLAYLEVEL(2, "/%6.*f%4s", file_hrs.precision, file_hrs.value, file_hrs.suffix); DISPLAYLEVEL(1, " ==> %2.f%%", cShare); DELAY_NEXT_UPDATE(); } @@ -1366,8 +1366,8 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, * or because input is slow and no job can start while waiting for at least one buffer to be filled. * note : exclude starting part, since currentJobID > 1 */ if ( (zfp.consumed == previous_zfp_update.consumed) /* no data compressed : no data available, or no more buffer to compress to, OR compression is really slow (compression of a single block is slower than update rate)*/ - && (zfp.nbActiveWorkers == 0) /* confirmed : no compression ongoing */ - ) { + && (zfp.nbActiveWorkers == 0) /* confirmed : no compression ongoing */ + ) { DISPLAYLEVEL(6, "all buffers full : compression stopped => slow down \n") speedChange = slower; } @@ -1375,8 +1375,8 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, previous_zfp_update = zfp; if ( (newlyProduced > (newlyFlushed * 9 / 8)) /* compression produces more data than output can flush (though production can be spiky, due to work unit : (N==4)*block sizes) */ - && (flushWaiting == 0) /* flush speed was never slowed by lack of production, so it's operating at max capacity */ - ) { + && (flushWaiting == 0) /* flush speed was never slowed by lack of production, so it's operating at max capacity */ + ) { DISPLAYLEVEL(6, "compression faster than flush (%llu > %llu), and flushed was never slowed down by lack of production => slow down \n", newlyProduced, newlyFlushed); speedChange = slower; } @@ -1400,15 +1400,15 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, previous_zfp_correction = zfp; assert(inputPresented > 0); DISPLAYLEVEL(6, "input blocked %u/%u(%.2f) - ingested:%u vs %u:consumed - flushed:%u vs %u:produced \n", - inputBlocked, inputPresented, (double)inputBlocked/inputPresented*100, - (unsigned)newlyIngested, (unsigned)newlyConsumed, - (unsigned)newlyFlushed, (unsigned)newlyProduced); + inputBlocked, inputPresented, (double)inputBlocked/inputPresented*100, + (unsigned)newlyIngested, (unsigned)newlyConsumed, + (unsigned)newlyFlushed, (unsigned)newlyProduced); if ( (inputBlocked > inputPresented / 8) /* input is waiting often, because input buffers is full : compression or output too slow */ - && (newlyFlushed * 33 / 32 > newlyProduced) /* flush everything that is produced */ - && (newlyIngested * 33 / 32 > newlyConsumed) /* input speed as fast or faster than compression speed */ - ) { + && (newlyFlushed * 33 / 32 > newlyProduced) /* flush everything that is produced */ + && (newlyIngested * 33 / 32 > newlyConsumed) /* input speed as fast or faster than compression speed */ + ) { DISPLAYLEVEL(6, "recommend faster as in(%llu) >= (%llu)comp(%llu) <= out(%llu) \n", - newlyIngested, newlyConsumed, newlyProduced, newlyFlushed); + newlyIngested, newlyConsumed, newlyProduced, newlyFlushed); speedChange = faster; } } @@ -1442,7 +1442,7 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, if (fileSize != UTIL_FILESIZE_UNKNOWN && *readsize != fileSize) { EXM_THROW(27, "Read error : Incomplete read : %llu / %llu B", - (unsigned long long)*readsize, (unsigned long long)fileSize); + (unsigned long long)*readsize, (unsigned long long)fileSize); } AIO_WritePool_releaseIoJob(writeJob); @@ -1504,7 +1504,7 @@ FIO_compressFilename_internal(FIO_ctx_t* const fCtx, #else (void)compressionLevel; EXM_THROW(20, "zstd: %s: file cannot be compressed as lz4 (zstd compiled without ZSTD_LZ4COMPRESS) -- ignored \n", - srcFileName); + srcFileName); #endif break; } @@ -1520,17 +1520,17 @@ FIO_compressFilename_internal(FIO_ctx_t* const fCtx, UTIL_HumanReadableSize_t hr_osize = UTIL_makeHumanReadableSize((U64) compressedfilesize); if (readsize == 0) { DISPLAYLEVEL(2,"%-20s : (%6.*f%4s => %6.*f%4s, %s) \n", - srcFileName, - hr_isize.precision, hr_isize.value, hr_isize.suffix, - hr_osize.precision, hr_osize.value, hr_osize.suffix, - dstFileName); + srcFileName, + hr_isize.precision, hr_isize.value, hr_isize.suffix, + hr_osize.precision, hr_osize.value, hr_osize.suffix, + dstFileName); } else { DISPLAYLEVEL(2,"%-20s :%6.2f%% (%6.*f%4s => %6.*f%4s, %s) \n", - srcFileName, - (double)compressedfilesize / (double)readsize * 100, - hr_isize.precision, hr_isize.value, hr_isize.suffix, - hr_osize.precision, hr_osize.value, hr_osize.suffix, - dstFileName); + srcFileName, + (double)compressedfilesize / (double)readsize * 100, + hr_isize.precision, hr_isize.value, hr_isize.suffix, + hr_osize.precision, hr_osize.value, hr_osize.suffix, + dstFileName); } } @@ -1541,7 +1541,7 @@ FIO_compressFilename_internal(FIO_ctx_t* const fCtx, double const timeLength_s = (double)timeLength_ns / 1000000000; double const cpuLoad_pct = (cpuLoad_s / timeLength_s) * 100; DISPLAYLEVEL(4, "%-20s : Completed in %.2f sec (cpu load : %.0f%%)\n", - srcFileName, timeLength_s, cpuLoad_pct); + srcFileName, timeLength_s, cpuLoad_pct); } return 0; } @@ -1572,9 +1572,9 @@ static int FIO_compressFilename_dstFile(FIO_ctx_t* const fCtx, if (AIO_WritePool_getFile(ress.writeCtx) == NULL) { int dstFilePermissions = DEFAULT_FILE_PERMISSIONS; if ( strcmp (srcFileName, stdinmark) - && strcmp (dstFileName, stdoutmark) - && UTIL_stat(srcFileName, &statbuf) - && UTIL_isRegularFileStat(&statbuf) ) { + && strcmp (dstFileName, stdoutmark) + && UTIL_stat(srcFileName, &statbuf) + && UTIL_isRegularFileStat(&statbuf) ) { dstFilePermissions = statbuf.st_mode; transferMTime = 1; } @@ -1605,8 +1605,8 @@ static int FIO_compressFilename_dstFile(FIO_ctx_t* const fCtx, UTIL_utime(dstFileName, &statbuf); } if ( (result != 0) /* operation failure */ - && strcmp(dstFileName, stdoutmark) /* special case : don't remove() stdout */ - ) { + && strcmp(dstFileName, stdoutmark) /* special case : don't remove() stdout */ + ) { FIO_removeFile(dstFileName); /* remove compression artefact; note don't do anything special if remove() fails */ } } @@ -1618,16 +1618,16 @@ static int FIO_compressFilename_dstFile(FIO_ctx_t* const fCtx, * Different from the suffixList and should only apply to ZSTD compress operationResult */ static const char *compressedFileExtensions[] = { - ZSTD_EXTENSION, - TZSTD_EXTENSION, - GZ_EXTENSION, - TGZ_EXTENSION, - LZMA_EXTENSION, - XZ_EXTENSION, - TXZ_EXTENSION, - LZ4_EXTENSION, - TLZ4_EXTENSION, - NULL + ZSTD_EXTENSION, + TZSTD_EXTENSION, + GZ_EXTENSION, + TGZ_EXTENSION, + LZMA_EXTENSION, + XZ_EXTENSION, + TXZ_EXTENSION, + LZ4_EXTENSION, + TLZ4_EXTENSION, + NULL }; /*! FIO_compressFilename_srcFile() : @@ -1675,15 +1675,15 @@ FIO_compressFilename_srcFile(FIO_ctx_t* const fCtx, ReadPool_closeFile(ress.readCtx); if ( prefs->removeSrcFile /* --rm */ - && result == 0 /* success */ - && strcmp(srcFileName, stdinmark) /* exception : don't erase stdin */ - ) { + && result == 0 /* success */ + && strcmp(srcFileName, stdinmark) /* exception : don't erase stdin */ + ) { /* We must clear the handler, since after this point calling it would * delete both the source and destination files. */ clearHandler(); if (FIO_removeFile(srcFileName)) - EXM_THROW(1, "zstd: %s: %s", srcFileName, strerror(errno)); + EXM_THROW(1, "zstd: %s: %s", srcFileName, strerror(errno)); } return result; } @@ -1814,8 +1814,8 @@ int FIO_compressMultipleFilenames(FIO_ctx_t* const fCtx, int status; int error = 0; cRess_t ress = FIO_createCResources(prefs, dictFileName, - FIO_getLargestFileSize(inFileNamesTable, (unsigned)fCtx->nbFilesTotal), - compressionLevel, comprParams); + FIO_getLargestFileSize(inFileNamesTable, (unsigned)fCtx->nbFilesTotal), + compressionLevel, comprParams); /* init */ assert(outFileName != NULL || suffix != NULL); @@ -1836,8 +1836,8 @@ int FIO_compressMultipleFilenames(FIO_ctx_t* const fCtx, error |= status; } if (AIO_WritePool_closeFile(ress.writeCtx)) - EXM_THROW(29, "Write error (%s) : cannot properly close %s", - strerror(errno), outFileName); + EXM_THROW(29, "Write error (%s) : cannot properly close %s", + strerror(errno), outFileName); } } else { if (outMirroredRootDirName) @@ -1874,10 +1874,10 @@ int FIO_compressMultipleFilenames(FIO_ctx_t* const fCtx, DISPLAYLEVEL(2, "\r%79s\r", ""); DISPLAYLEVEL(2, "%3d files compressed :%.2f%% (%6.*f%4s => %6.*f%4s)\n", - fCtx->nbFilesProcessed, - (double)fCtx->totalBytesOutput/((double)fCtx->totalBytesInput)*100, - hr_isize.precision, hr_isize.value, hr_isize.suffix, - hr_osize.precision, hr_osize.value, hr_osize.suffix); + fCtx->nbFilesProcessed, + (double)fCtx->totalBytesOutput/((double)fCtx->totalBytesInput)*100, + hr_isize.precision, hr_isize.value, hr_isize.suffix, + hr_osize.precision, hr_osize.value, hr_osize.suffix); } FIO_freeCResources(&ress); @@ -1978,16 +1978,16 @@ FIO_zstdErrorHelp(const FIO_prefs_t* const prefs, unsigned const windowLog = FIO_highbit64(windowSize) + ((windowSize & (windowSize - 1)) != 0); assert(prefs->memLimit > 0); DISPLAYLEVEL(1, "%s : Window size larger than maximum : %llu > %u \n", - srcFileName, windowSize, prefs->memLimit); + srcFileName, windowSize, prefs->memLimit); if (windowLog <= ZSTD_WINDOWLOG_MAX) { unsigned const windowMB = (unsigned)((windowSize >> 20) + ((windowSize & ((1 MB) - 1)) != 0)); assert(windowSize < (U64)(1ULL << 52)); /* ensure now overflow for windowMB */ DISPLAYLEVEL(1, "%s : Use --long=%u or --memory=%uMB \n", - srcFileName, windowLog, windowMB); + srcFileName, windowLog, windowMB); return; - } } + } } DISPLAYLEVEL(1, "%s : Window log larger than ZSTD_WINDOWLOG_MAX=%u; not supported \n", - srcFileName, ZSTD_WINDOWLOG_MAX); + srcFileName, ZSTD_WINDOWLOG_MAX); } /** FIO_decompressFrame() : @@ -2023,7 +2023,7 @@ FIO_decompressZstdFrame(FIO_ctx_t* const fCtx, dRess_t* ress, UTIL_HumanReadableSize_t const hrs = UTIL_makeHumanReadableSize(alreadyDecoded+frameSize); if (ZSTD_isError(readSizeHint)) { DISPLAYLEVEL(1, "%s : Decoding error (36) : %s \n", - srcFileName, ZSTD_getErrorName(readSizeHint)); + srcFileName, ZSTD_getErrorName(readSizeHint)); FIO_zstdErrorHelp(prefs, ress, readSizeHint, srcFileName); AIO_WritePool_releaseIoJob(writeJob); return FIO_ERROR_FRAME_DECODING; @@ -2041,11 +2041,11 @@ FIO_decompressZstdFrame(FIO_ctx_t* const fCtx, dRess_t* ress, fCtx->currFileIdx+1, fCtx->nbFilesTotal, truncatedSrcFileName, hrs.precision, hrs.value, hrs.suffix); } else { DISPLAYUPDATE(displayLevel, "\rDecompress: %2u/%2u files. Current: %s : %.*f%s... ", - fCtx->currFileIdx+1, fCtx->nbFilesTotal, srcFileName, hrs.precision, hrs.value, hrs.suffix); + fCtx->currFileIdx+1, fCtx->nbFilesTotal, srcFileName, hrs.precision, hrs.value, hrs.suffix); } } else { DISPLAYUPDATE(displayLevel, "\r%-20.20s : %.*f%s... ", - srcFileName, hrs.precision, hrs.value, hrs.suffix); + srcFileName, hrs.precision, hrs.value, hrs.suffix); } ReadPool_consumeBytes(ress->readCtx, inBuff.pos); @@ -2128,7 +2128,7 @@ FIO_decompressGzFrame(dRess_t* ress, const char* srcFileName) ReadPool_consumeBytes(ress->readCtx, ress->readCtx->srcBufferLoaded - strm.avail_in); if ( (inflateEnd(&strm) != Z_OK) /* release resources ; error detected */ - && (decodingError==0) ) { + && (decodingError==0) ) { DISPLAYLEVEL(1, "zstd: %s: inflateEnd error \n", srcFileName); decodingError = 1; } @@ -2327,7 +2327,7 @@ static int FIO_decompressFrames(FIO_ctx_t* const fCtx, return 1; #endif } else if ((buf[0] == 0xFD && buf[1] == 0x37) /* xz magic number */ - || (buf[0] == 0x5D && buf[1] == 0x00)) { /* lzma header (no magic number) */ + || (buf[0] == 0x5D && buf[1] == 0x00)) { /* lzma header (no magic number) */ #ifdef ZSTD_LZMADECOMPRESS unsigned long long const frameSize = FIO_decompressLzmaFrame(&ress, srcFileName, buf[0] != 0xFD); if (frameSize == FIO_ERROR_FRAME_DECODING) return 1; @@ -2350,7 +2350,7 @@ static int FIO_decompressFrames(FIO_ctx_t* const fCtx, } else { DISPLAYLEVEL(1, "zstd: %s: unsupported format \n", srcFileName); return 1; - } } /* for each frame */ + } } /* for each frame */ /* Final Status */ fCtx->totalBytesOutput += (size_t)filesize; @@ -2385,9 +2385,9 @@ static int FIO_decompressDstFile(FIO_ctx_t* const fCtx, FILE *dstFile; int dstFilePermissions = DEFAULT_FILE_PERMISSIONS; if ( strcmp(srcFileName, stdinmark) /* special case : don't transfer permissions from stdin */ - && strcmp(dstFileName, stdoutmark) - && UTIL_stat(srcFileName, &statbuf) - && UTIL_isRegularFileStat(&statbuf) ) { + && strcmp(dstFileName, stdoutmark) + && UTIL_stat(srcFileName, &statbuf) + && UTIL_isRegularFileStat(&statbuf) ) { dstFilePermissions = statbuf.st_mode; transferMTime = 1; } @@ -2419,8 +2419,8 @@ static int FIO_decompressDstFile(FIO_ctx_t* const fCtx, } if ( (result != 0) /* operation failure */ - && strcmp(dstFileName, stdoutmark) /* special case : don't remove() stdout */ - ) { + && strcmp(dstFileName, stdoutmark) /* special case : don't remove() stdout */ + ) { FIO_removeFile(dstFileName); /* remove decompression artefact; note: don't do anything special if remove() fails */ } } @@ -2458,8 +2458,8 @@ static int FIO_decompressSrcFile(FIO_ctx_t* const fCtx, FIO_prefs_t* const prefs return 1; } if ( prefs->removeSrcFile /* --rm */ - && (result==0) /* decompression successful */ - && strcmp(srcFileName, stdinmark) ) /* not stdin */ { + && (result==0) /* decompression successful */ + && strcmp(srcFileName, stdinmark) ) /* not stdin */ { /* We must clear the handler, since after this point calling it would * delete both the source and destination files. */ @@ -2468,7 +2468,7 @@ static int FIO_decompressSrcFile(FIO_ctx_t* const fCtx, FIO_prefs_t* const prefs /* failed to remove src file */ DISPLAYLEVEL(1, "zstd: %s: %s \n", srcFileName, strerror(errno)); return 1; - } } + } } return result; } @@ -2487,37 +2487,37 @@ int FIO_decompressFilename(FIO_ctx_t* const fCtx, FIO_prefs_t* const prefs, } static const char *suffixList[] = { - ZSTD_EXTENSION, - TZSTD_EXTENSION, + ZSTD_EXTENSION, + TZSTD_EXTENSION, #ifndef ZSTD_NODECOMPRESS - ZSTD_ALT_EXTENSION, + ZSTD_ALT_EXTENSION, #endif #ifdef ZSTD_GZDECOMPRESS - GZ_EXTENSION, - TGZ_EXTENSION, + GZ_EXTENSION, + TGZ_EXTENSION, #endif #ifdef ZSTD_LZMADECOMPRESS - LZMA_EXTENSION, + LZMA_EXTENSION, XZ_EXTENSION, TXZ_EXTENSION, #endif #ifdef ZSTD_LZ4DECOMPRESS - LZ4_EXTENSION, + LZ4_EXTENSION, TLZ4_EXTENSION, #endif - NULL + NULL }; static const char *suffixListStr = - ZSTD_EXTENSION "/" TZSTD_EXTENSION - #ifdef ZSTD_GZDECOMPRESS - "/" GZ_EXTENSION "/" TGZ_EXTENSION + ZSTD_EXTENSION "/" TZSTD_EXTENSION +#ifdef ZSTD_GZDECOMPRESS + "/" GZ_EXTENSION "/" TGZ_EXTENSION #endif #ifdef ZSTD_LZMADECOMPRESS -"/" LZMA_EXTENSION "/" XZ_EXTENSION "/" TXZ_EXTENSION + "/" LZMA_EXTENSION "/" XZ_EXTENSION "/" TXZ_EXTENSION #endif #ifdef ZSTD_LZ4DECOMPRESS -"/" LZ4_EXTENSION "/" TLZ4_EXTENSION + "/" LZ4_EXTENSION "/" TLZ4_EXTENSION #endif ; @@ -2541,10 +2541,10 @@ FIO_determineDstName(const char* srcFileName, const char* outDirName) const char* const srcSuffix = strrchr(srcFileName, '.'); if (srcSuffix == NULL) { DISPLAYLEVEL(1, - "zstd: %s: unknown suffix (%s expected). " - "Can't derive the output file name. " - "Specify it with -o dstFileName. Ignoring.\n", - srcFileName, suffixListStr); + "zstd: %s: unknown suffix (%s expected). " + "Can't derive the output file name. " + "Specify it with -o dstFileName. Ignoring.\n", + srcFileName, suffixListStr); return NULL; } srcSuffixLen = strlen(srcSuffix); @@ -2560,10 +2560,10 @@ FIO_determineDstName(const char* srcFileName, const char* outDirName) /* check suffix is authorized */ if (sfnSize <= srcSuffixLen || *matchedSuffixPtr == NULL) { DISPLAYLEVEL(1, - "zstd: %s: unknown suffix (%s expected). " - "Can't derive the output file name. " - "Specify it with -o dstFileName. Ignoring.\n", - srcFileName, suffixListStr); + "zstd: %s: unknown suffix (%s expected). " + "Can't derive the output file name. " + "Specify it with -o dstFileName. Ignoring.\n", + srcFileName, suffixListStr); return NULL; } @@ -2585,8 +2585,8 @@ FIO_determineDstName(const char* srcFileName, const char* outDirName) dfnbCapacity = sfnSize + 20; dstFileNameBuffer = (char*)malloc(dfnbCapacity); if (dstFileNameBuffer==NULL) - EXM_THROW(74, "%s : not enough memory for dstFileName", - strerror(errno)); + EXM_THROW(74, "%s : not enough memory for dstFileName", + strerror(errno)); } /* return dst name == src name truncated from suffix */ @@ -2635,8 +2635,8 @@ FIO_decompressMultipleFilenames(FIO_ctx_t* const fCtx, error |= status; } if ((!prefs->testMode) && (AIO_WritePool_closeFile(ress.writeCtx))) - EXM_THROW(72, "Write error : %s : cannot properly close output file", - strerror(errno)); + EXM_THROW(72, "Write error : %s : cannot properly close output file", + strerror(errno)); } else { if (outMirroredRootDirName) UTIL_mirrorSourceFilesDirectories(srcNamesTable, (unsigned)fCtx->nbFilesTotal, outMirroredRootDirName); @@ -2665,7 +2665,7 @@ FIO_decompressMultipleFilenames(FIO_ctx_t* const fCtx, } if (fCtx->nbFilesProcessed >= 1 && fCtx->nbFilesTotal > 1 && fCtx->totalBytesOutput != 0) - DISPLAYLEVEL(2, "%d files decompressed : %6zu bytes total \n", fCtx->nbFilesProcessed, fCtx->totalBytesOutput); + DISPLAYLEVEL(2, "%d files decompressed : %6zu bytes total \n", fCtx->nbFilesProcessed, fCtx->totalBytesOutput); FIO_freeDResources(ress); return error; @@ -2687,11 +2687,11 @@ typedef struct { } fileInfo_t; typedef enum { - info_success=0, - info_frame_error=1, - info_not_zstd=2, - info_file_error=3, - info_truncated_input=4, + info_success=0, + info_frame_error=1, + info_not_zstd=2, + info_file_error=3, + info_truncated_input=4, } InfoError; #define ERROR_IF(c,n,...) { \ @@ -2711,15 +2711,15 @@ FIO_analyzeFrames(fileInfo_t* info, FILE* const srcFile) size_t const numBytesRead = fread(headerBuffer, 1, sizeof(headerBuffer), srcFile); if (numBytesRead < ZSTD_FRAMEHEADERSIZE_MIN(ZSTD_f_zstd1)) { if ( feof(srcFile) - && (numBytesRead == 0) - && (info->compressedSize > 0) - && (info->compressedSize != UTIL_FILESIZE_UNKNOWN) ) { + && (numBytesRead == 0) + && (info->compressedSize > 0) + && (info->compressedSize != UTIL_FILESIZE_UNKNOWN) ) { unsigned long long file_position = (unsigned long long) LONG_TELL(srcFile); unsigned long long file_size = (unsigned long long) info->compressedSize; ERROR_IF(file_position != file_size, info_truncated_input, - "Error: seeked to position %llu, which is beyond file size of %llu\n", - file_position, - file_size); + "Error: seeked to position %llu, which is beyond file size of %llu\n", + file_position, + file_size); break; /* correct end of file => success */ } ERROR_IF(feof(srcFile), info_not_zstd, "Error: reached end of file with incomplete frame"); @@ -2731,19 +2731,19 @@ FIO_analyzeFrames(fileInfo_t* info, FILE* const srcFile) ZSTD_frameHeader header; U64 const frameContentSize = ZSTD_getFrameContentSize(headerBuffer, numBytesRead); if ( frameContentSize == ZSTD_CONTENTSIZE_ERROR - || frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN ) { + || frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN ) { info->decompUnavailable = 1; } else { info->decompressedSize += frameContentSize; } ERROR_IF(ZSTD_getFrameHeader(&header, headerBuffer, numBytesRead) != 0, - info_frame_error, "Error: could not decode frame header"); + info_frame_error, "Error: could not decode frame header"); info->windowSize = header.windowSize; /* move to the end of the frame header */ { size_t const headerSize = ZSTD_frameHeaderSize(headerBuffer, numBytesRead); ERROR_IF(ZSTD_isError(headerSize), info_frame_error, "Error: could not determine frame header size"); ERROR_IF(fseek(srcFile, ((long)headerSize)-((long)numBytesRead), SEEK_CUR) != 0, - info_frame_error, "Error: could not move to end of frame header"); + info_frame_error, "Error: could not move to end of frame header"); } /* skip all blocks in the frame */ @@ -2751,7 +2751,7 @@ FIO_analyzeFrames(fileInfo_t* info, FILE* const srcFile) do { BYTE blockHeaderBuffer[3]; ERROR_IF(fread(blockHeaderBuffer, 1, 3, srcFile) != 3, - info_frame_error, "Error while reading block header"); + info_frame_error, "Error while reading block header"); { U32 const blockHeader = MEM_readLE24(blockHeaderBuffer); U32 const blockTypeID = (blockHeader >> 1) & 3; U32 const isRLE = (blockTypeID == 1); @@ -2760,7 +2760,7 @@ FIO_analyzeFrames(fileInfo_t* info, FILE* const srcFile) ERROR_IF(isWrongBlock, info_frame_error, "Error: unsupported block type"); lastBlock = blockHeader & 1; ERROR_IF(fseek(srcFile, blockSize, SEEK_CUR) != 0, - info_frame_error, "Error: could not skip to end of block"); + info_frame_error, "Error: could not skip to end of block"); } } while (lastBlock != 1); } @@ -2771,19 +2771,19 @@ FIO_analyzeFrames(fileInfo_t* info, FILE* const srcFile) if (contentChecksumFlag) { info->usesCheck = 1; ERROR_IF(fseek(srcFile, 4, SEEK_CUR) != 0, - info_frame_error, "Error: could not skip past checksum"); - } } + info_frame_error, "Error: could not skip past checksum"); + } } info->numActualFrames++; } - /* Skippable frame */ + /* Skippable frame */ else if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { U32 const frameSize = MEM_readLE32(headerBuffer + 4); long const seek = (long)(8 + frameSize - numBytesRead); ERROR_IF(LONG_SEEK(srcFile, seek, SEEK_CUR) != 0, - info_frame_error, "Error: could not find end of skippable frame"); + info_frame_error, "Error: could not find end of skippable frame"); info->numSkippableFrames++; } - /* unknown content */ + /* unknown content */ else { return info_not_zstd; } @@ -2817,7 +2817,7 @@ static InfoError getFileInfo(fileInfo_t* info, const char* srcFileName) { ERROR_IF(!UTIL_isRegularFile(srcFileName), - info_file_error, "Error : %s is not a file", srcFileName); + info_file_error, "Error : %s is not a file", srcFileName); return getFileInfo_fileConfirmed(info, srcFileName); } @@ -2833,17 +2833,17 @@ displayInfo(const char* inFileName, const fileInfo_t* info, int displayLevel) if (displayLevel <= 2) { if (!info->decompUnavailable) { DISPLAYOUT("%6d %5d %6.*f%4s %8.*f%4s %5.3f %5s %s\n", - info->numSkippableFrames + info->numActualFrames, - info->numSkippableFrames, - compressed_hrs.precision, compressed_hrs.value, compressed_hrs.suffix, - decompressed_hrs.precision, decompressed_hrs.value, decompressed_hrs.suffix, - ratio, checkString, inFileName); + info->numSkippableFrames + info->numActualFrames, + info->numSkippableFrames, + compressed_hrs.precision, compressed_hrs.value, compressed_hrs.suffix, + decompressed_hrs.precision, decompressed_hrs.value, decompressed_hrs.suffix, + ratio, checkString, inFileName); } else { DISPLAYOUT("%6d %5d %6.*f%4s %5s %s\n", - info->numSkippableFrames + info->numActualFrames, - info->numSkippableFrames, - compressed_hrs.precision, compressed_hrs.value, compressed_hrs.suffix, - checkString, inFileName); + info->numSkippableFrames + info->numActualFrames, + info->numSkippableFrames, + compressed_hrs.precision, compressed_hrs.value, compressed_hrs.suffix, + checkString, inFileName); } } else { DISPLAYOUT("%s \n", inFileName); @@ -2854,12 +2854,12 @@ displayInfo(const char* inFileName, const fileInfo_t* info, int displayLevel) window_hrs.precision, window_hrs.value, window_hrs.suffix, (unsigned long long)info->windowSize); DISPLAYOUT("Compressed Size: %.*f%s (%llu B)\n", - compressed_hrs.precision, compressed_hrs.value, compressed_hrs.suffix, - (unsigned long long)info->compressedSize); + compressed_hrs.precision, compressed_hrs.value, compressed_hrs.suffix, + (unsigned long long)info->compressedSize); if (!info->decompUnavailable) { DISPLAYOUT("Decompressed Size: %.*f%s (%llu B)\n", - decompressed_hrs.precision, decompressed_hrs.value, decompressed_hrs.suffix, - (unsigned long long)info->decompressedSize); + decompressed_hrs.precision, decompressed_hrs.value, decompressed_hrs.suffix, + (unsigned long long)info->decompressedSize); DISPLAYOUT("Ratio: %.4f\n", ratio); } DISPLAYOUT("Check: %s\n", checkString); @@ -2890,7 +2890,7 @@ FIO_listFile(fileInfo_t* total, const char* inFileName, int displayLevel) switch (error) { case info_frame_error: /* display error, but provide output */ - DISPLAYLEVEL(1, "Error while parsing \"%s\" \n", inFileName); + DISPLAYLEVEL(1, "Error while parsing \"%s\" \n", inFileName); break; case info_not_zstd: DISPLAYOUT("File \"%s\" not compressed by zstd \n", inFileName); @@ -2922,8 +2922,8 @@ int FIO_listMultipleFiles(unsigned numFiles, const char** filenameTable, int dis { unsigned u; for (u=0; u 1 && displayLevel <= 2) { /* display total */ UTIL_HumanReadableSize_t const compressed_hrs = UTIL_makeHumanReadableSize(total.compressedSize); UTIL_HumanReadableSize_t const decompressed_hrs = UTIL_makeHumanReadableSize(total.decompressedSize); @@ -2953,18 +2953,18 @@ int FIO_listMultipleFiles(unsigned numFiles, const char** filenameTable, int dis DISPLAYOUT("----------------------------------------------------------------- \n"); if (total.decompUnavailable) { DISPLAYOUT("%6d %5d %6.*f%4s %5s %u files\n", - total.numSkippableFrames + total.numActualFrames, - total.numSkippableFrames, - compressed_hrs.precision, compressed_hrs.value, compressed_hrs.suffix, - checkString, (unsigned)total.nbFiles); + total.numSkippableFrames + total.numActualFrames, + total.numSkippableFrames, + compressed_hrs.precision, compressed_hrs.value, compressed_hrs.suffix, + checkString, (unsigned)total.nbFiles); } else { DISPLAYOUT("%6d %5d %6.*f%4s %8.*f%4s %5.3f %5s %u files\n", - total.numSkippableFrames + total.numActualFrames, - total.numSkippableFrames, - compressed_hrs.precision, compressed_hrs.value, compressed_hrs.suffix, - decompressed_hrs.precision, decompressed_hrs.value, decompressed_hrs.suffix, - ratio, checkString, (unsigned)total.nbFiles); - } } + total.numSkippableFrames + total.numActualFrames, + total.numSkippableFrames, + compressed_hrs.precision, compressed_hrs.value, compressed_hrs.suffix, + decompressed_hrs.precision, decompressed_hrs.value, decompressed_hrs.suffix, + ratio, checkString, (unsigned)total.nbFiles); + } } return error; } } From 7366119dd023fc8dcdd7d38d22cce6d9e84e95f2 Mon Sep 17 00:00:00 2001 From: Yonatan Komornik Date: Mon, 24 Jan 2022 14:23:36 -0800 Subject: [PATCH 08/23] CR fixes (naming conventions) --- programs/fileio.c | 68 ++++++++++++++--------------- programs/fileio_asyncio.c | 90 +++++++++++++++++++-------------------- programs/fileio_asyncio.h | 34 +++++++-------- 3 files changed, 96 insertions(+), 96 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index ec5fa49431f..b246d577c1a 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -819,7 +819,7 @@ typedef struct { const char* dictFileName; ZSTD_CStream* cctx; WritePoolCtx_t *writeCtx; - read_pool_ctx_t *readCtx; + ReadPoolCtx_t *readCtx; } cRess_t; /** ZSTD_cycleLog() : @@ -878,7 +878,7 @@ static cRess_t FIO_createCResources(FIO_prefs_t* const prefs, ress.dictBufferSize = FIO_createDictBuffer(&ress.dictBuffer, dictFileName, prefs); /* works with dictFileName==NULL */ ress.writeCtx = AIO_WritePool_create(prefs, ZSTD_CStreamOutSize()); - ress.readCtx = ReadPool_create(prefs, ZSTD_CStreamInSize()); + ress.readCtx = AIO_ReadPool_create(prefs, ZSTD_CStreamInSize()); /* Advanced parameters, including dictionary */ if (dictFileName && (ress.dictBuffer==NULL)) @@ -943,7 +943,7 @@ static void FIO_freeCResources(const cRess_t* const ress) { free(ress->dictBuffer); AIO_WritePool_free(ress->writeCtx); - ReadPool_free(ress->readCtx); + AIO_ReadPool_free(ress->readCtx); ZSTD_freeCStream(ress->cctx); /* never fails */ } @@ -981,7 +981,7 @@ FIO_compressGzFrame(const cRess_t* ress, /* buffers & handlers are used, but no while (1) { int ret; if (strm.avail_in == 0) { - ReadPool_fillBuffer(ress->readCtx, ZSTD_CStreamInSize()); + AIO_ReadPool_fillBuffer(ress->readCtx, ZSTD_CStreamInSize()); if (ress->readCtx->srcBufferLoaded == 0) break; inFileSize += ress->readCtx->srcBufferLoaded; strm.next_in = (z_const unsigned char*)ress->readCtx->srcBuffer; @@ -991,7 +991,7 @@ FIO_compressGzFrame(const cRess_t* ress, /* buffers & handlers are used, but no { size_t const availBefore = strm.avail_in; ret = deflate(&strm, Z_NO_FLUSH); - ReadPool_consumeBytes(ress->readCtx, availBefore - strm.avail_in); + AIO_ReadPool_consumeBytes(ress->readCtx, availBefore - strm.avail_in); } if (ret != Z_OK) @@ -1077,7 +1077,7 @@ FIO_compressLzmaFrame(cRess_t* ress, while (1) { if (strm.avail_in == 0) { - size_t const inSize = ReadPool_fillBuffer(ress->readCtx, ZSTD_CStreamInSize()); + size_t const inSize = AIO_ReadPool_fillBuffer(ress->readCtx, ZSTD_CStreamInSize()); if (ress->readCtx->srcBufferLoaded == 0) action = LZMA_FINISH; inFileSize += inSize; strm.next_in = (BYTE const*)ress->readCtx->srcBuffer; @@ -1087,7 +1087,7 @@ FIO_compressLzmaFrame(cRess_t* ress, { size_t const availBefore = strm.avail_in; ret = lzma_code(&strm, action); - ReadPool_consumeBytes(ress->readCtx, availBefore - strm.avail_in); + AIO_ReadPool_consumeBytes(ress->readCtx, availBefore - strm.avail_in); } @@ -1174,7 +1174,7 @@ FIO_compressLz4Frame(cRess_t* ress, outFileSize += headerSize; /* Read first block */ - readSize = ReadPool_fillBuffer(ress->readCtx, blockSize); + readSize = AIO_ReadPool_fillBuffer(ress->readCtx, blockSize); inFileSize += readSize; /* Main Loop */ @@ -1200,8 +1200,8 @@ FIO_compressLz4Frame(cRess_t* ress, AIO_WritePool_enqueueAndReacquireWriteJob(&writeJob); /* Read next block */ - ReadPool_consumeBytes(ress->readCtx, ress->readCtx->srcBufferLoaded); - readSize = ReadPool_fillBuffer(ress->readCtx, blockSize); + AIO_ReadPool_consumeBytes(ress->readCtx, ress->readCtx->srcBufferLoaded); + readSize = AIO_ReadPool_fillBuffer(ress->readCtx, blockSize); inFileSize += readSize; } @@ -1234,7 +1234,7 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, int compressionLevel, U64* readsize) { cRess_t const ress = *ressPtr; - IOJob_t *writeJob =AIO_WritePool_acquireJob(ressPtr->writeCtx); + IOJob_t *writeJob = AIO_WritePool_acquireJob(ressPtr->writeCtx); U64 compressedfilesize = 0; ZSTD_EndDirective directive = ZSTD_e_continue; @@ -1280,7 +1280,7 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, do { size_t stillToFlush; /* Fill input Buffer */ - size_t const inSize = ReadPool_fillBuffer(ress.readCtx, ZSTD_CStreamInSize()); + size_t const inSize = AIO_ReadPool_fillBuffer(ress.readCtx, ZSTD_CStreamInSize()); ZSTD_inBuffer inBuff = { ress.readCtx->srcBuffer, ress.readCtx->srcBufferLoaded, 0 }; DISPLAYLEVEL(6, "fread %u bytes from source \n", (unsigned)inSize); *readsize += inSize; @@ -1296,7 +1296,7 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, ZSTD_outBuffer outBuff= { writeJob->buffer, writeJob->bufferSize, 0 }; size_t const toFlushNow = ZSTD_toFlushNow(ress.cctx); CHECK_V(stillToFlush, ZSTD_compressStream2(ress.cctx, &outBuff, &inBuff, directive)); - ReadPool_consumeBytes(ress.readCtx, inBuff.pos - oldIPos); + AIO_ReadPool_consumeBytes(ress.readCtx, inBuff.pos - oldIPos); /* count stats */ inputPresented++; @@ -1568,7 +1568,7 @@ static int FIO_compressFilename_dstFile(FIO_ctx_t* const fCtx, stat_t statbuf; int transferMTime = 0; FILE *dstFile; - assert(ReadPool_getFile(ress.readCtx) != NULL); + assert(AIO_ReadPool_getFile(ress.readCtx) != NULL); if (AIO_WritePool_getFile(ress.writeCtx) == NULL) { int dstFilePermissions = DEFAULT_FILE_PERMISSIONS; if ( strcmp (srcFileName, stdinmark) @@ -1670,9 +1670,9 @@ FIO_compressFilename_srcFile(FIO_ctx_t* const fCtx, srcFile = FIO_openSrcFile(prefs, srcFileName); if (srcFile == NULL) return 1; /* srcFile could not be opened */ - ReadPool_setFile(ress.readCtx, srcFile); + AIO_ReadPool_setFile(ress.readCtx, srcFile); result = FIO_compressFilename_dstFile(fCtx, prefs, ress, dstFileName, srcFileName, compressionLevel); - ReadPool_closeFile(ress.readCtx); + AIO_ReadPool_closeFile(ress.readCtx); if ( prefs->removeSrcFile /* --rm */ && result == 0 /* success */ @@ -1896,7 +1896,7 @@ int FIO_compressMultipleFilenames(FIO_ctx_t* const fCtx, typedef struct { ZSTD_DStream* dctx; WritePoolCtx_t *writeCtx; - read_pool_ctx_t *readCtx; + ReadPoolCtx_t *readCtx; } dRess_t; static dRess_t FIO_createDResources(FIO_prefs_t* const prefs, const char* dictFileName) @@ -1922,7 +1922,7 @@ static dRess_t FIO_createDResources(FIO_prefs_t* const prefs, const char* dictFi } ress.writeCtx = AIO_WritePool_create(prefs, ZSTD_DStreamOutSize()); - ress.readCtx = ReadPool_create(prefs, ZSTD_DStreamInSize()); + ress.readCtx = AIO_ReadPool_create(prefs, ZSTD_DStreamInSize()); return ress; } @@ -1931,7 +1931,7 @@ static void FIO_freeDResources(dRess_t ress) { CHECK( ZSTD_freeDStream(ress.dctx) ); AIO_WritePool_free(ress.writeCtx); - ReadPool_free(ress.readCtx); + AIO_ReadPool_free(ress.readCtx); } /** FIO_passThrough() : just copy input into output, for compatibility with gzip -df mode @@ -1940,17 +1940,17 @@ static int FIO_passThrough(dRess_t *ress) { size_t const blockSize = MIN(MIN(64 KB, ZSTD_DStreamInSize()), ZSTD_DStreamOutSize()); IOJob_t *writeJob = AIO_WritePool_acquireJob(ress->writeCtx); - ReadPool_fillBuffer(ress->readCtx, blockSize); + AIO_ReadPool_fillBuffer(ress->readCtx, blockSize); while(ress->readCtx->srcBufferLoaded) { size_t writeSize; - ReadPool_fillBuffer(ress->readCtx, blockSize); + AIO_ReadPool_fillBuffer(ress->readCtx, blockSize); writeSize = MIN(blockSize, ress->readCtx->srcBufferLoaded); assert(writeSize <= writeJob->bufferSize); memcpy(writeJob->buffer, ress->readCtx->srcBuffer, writeSize); writeJob->usedBufferSize = writeSize; AIO_WritePool_enqueueAndReacquireWriteJob(&writeJob); - ReadPool_consumeBytes(ress->readCtx, writeSize); + AIO_ReadPool_consumeBytes(ress->readCtx, writeSize); } assert(ress->readCtx->reachedEof); AIO_WritePool_releaseIoJob(writeJob); @@ -2012,7 +2012,7 @@ FIO_decompressZstdFrame(FIO_ctx_t* const fCtx, dRess_t* ress, /* Header loading : ensures ZSTD_getFrameHeader() will succeed */ if (ress->readCtx->srcBufferLoaded < ZSTD_FRAMEHEADERSIZE_MAX) - ReadPool_fillBuffer(ress->readCtx, ZSTD_FRAMEHEADERSIZE_MAX); + AIO_ReadPool_fillBuffer(ress->readCtx, ZSTD_FRAMEHEADERSIZE_MAX); /* Main decompression Loop */ while (1) { @@ -2048,14 +2048,14 @@ FIO_decompressZstdFrame(FIO_ctx_t* const fCtx, dRess_t* ress, srcFileName, hrs.precision, hrs.value, hrs.suffix); } - ReadPool_consumeBytes(ress->readCtx, inBuff.pos); + AIO_ReadPool_consumeBytes(ress->readCtx, inBuff.pos); if (readSizeHint == 0) break; /* end of frame */ /* Fill input buffer */ { size_t const toDecode = MIN(readSizeHint, ZSTD_DStreamInSize()); /* support large skippable frames */ if (ress->readCtx->srcBufferLoaded < toDecode) { - size_t const readSize = ReadPool_fillBuffer(ress->readCtx, toDecode); + size_t const readSize = AIO_ReadPool_fillBuffer(ress->readCtx, toDecode); if (readSize==0) { DISPLAYLEVEL(1, "%s : Read error (39) : premature end \n", srcFileName); @@ -2099,7 +2099,7 @@ FIO_decompressGzFrame(dRess_t* ress, const char* srcFileName) for ( ; ; ) { int ret; if (strm.avail_in == 0) { - ReadPool_consumeAndRefill(ress->readCtx); + AIO_ReadPool_consumeAndRefill(ress->readCtx); if (ress->readCtx->srcBufferLoaded == 0) flush = Z_FINISH; strm.next_in = (z_const unsigned char*)ress->readCtx->srcBuffer; strm.avail_in = (uInt)ress->readCtx->srcBufferLoaded; @@ -2125,7 +2125,7 @@ FIO_decompressGzFrame(dRess_t* ress, const char* srcFileName) if (ret == Z_STREAM_END) break; } - ReadPool_consumeBytes(ress->readCtx, ress->readCtx->srcBufferLoaded - strm.avail_in); + AIO_ReadPool_consumeBytes(ress->readCtx, ress->readCtx->srcBufferLoaded - strm.avail_in); if ( (inflateEnd(&strm) != Z_OK) /* release resources ; error detected */ && (decodingError==0) ) { @@ -2174,7 +2174,7 @@ FIO_decompressLzmaFrame(dRess_t* ress, for ( ; ; ) { lzma_ret ret; if (strm.avail_in == 0) { - ReadPool_consumeAndRefill(ress->readCtx); + AIO_ReadPool_consumeAndRefill(ress->readCtx); if (ress->readCtx->srcBufferLoaded == 0) action = LZMA_FINISH; strm.next_in = (BYTE const*)ress->readCtx->srcBuffer; strm.avail_in = ress->readCtx->srcBufferLoaded; @@ -2201,7 +2201,7 @@ FIO_decompressLzmaFrame(dRess_t* ress, if (ret == LZMA_STREAM_END) break; } - ReadPool_consumeBytes(ress->readCtx, ress->readCtx->srcBufferLoaded - strm.avail_in); + AIO_ReadPool_consumeBytes(ress->readCtx, ress->readCtx->srcBufferLoaded - strm.avail_in); lzma_end(&strm); AIO_WritePool_releaseIoJob(writeJob); AIO_WritePool_sparseWriteEnd(ress->writeCtx); @@ -2234,7 +2234,7 @@ FIO_decompressLz4Frame(dRess_t* ress, const char* srcFileName) int fullBufferDecoded = 0; /* Read input */ - ReadPool_fillBuffer(ress->readCtx, nextToLoad); + AIO_ReadPool_fillBuffer(ress->readCtx, nextToLoad); if(!ress->readCtx->srcBufferLoaded) break; /* reached end of file */ while ((pos < ress->readCtx->srcBufferLoaded) || fullBufferDecoded) { /* still to read, or still to flush */ @@ -2264,7 +2264,7 @@ FIO_decompressLz4Frame(dRess_t* ress, const char* srcFileName) if (!nextToLoad) break; } - ReadPool_consumeBytes(ress->readCtx, pos); + AIO_ReadPool_consumeBytes(ress->readCtx, pos); } if (nextToLoad!=0) { DISPLAYLEVEL(1, "zstd: %s: unfinished lz4 stream \n", srcFileName); @@ -2299,7 +2299,7 @@ static int FIO_decompressFrames(FIO_ctx_t* const fCtx, /* check magic number -> version */ size_t const toRead = 4; const BYTE* buf; - ReadPool_fillBuffer(ress.readCtx, toRead); + AIO_ReadPool_fillBuffer(ress.readCtx, toRead); buf = (const BYTE*)ress.readCtx->srcBuffer; if (ress.readCtx->srcBufferLoaded==0) { if (readSomething==0) { /* srcFile is empty (which is invalid) */ @@ -2446,11 +2446,11 @@ static int FIO_decompressSrcFile(FIO_ctx_t* const fCtx, FIO_prefs_t* const prefs srcFile = FIO_openSrcFile(prefs, srcFileName); if (srcFile==NULL) return 1; - ReadPool_setFile(ress.readCtx, srcFile); + AIO_ReadPool_setFile(ress.readCtx, srcFile); result = FIO_decompressDstFile(fCtx, prefs, ress, dstFileName, srcFileName); - ReadPool_setFile(ress.readCtx, NULL); + AIO_ReadPool_setFile(ress.readCtx, NULL); /* Close file */ if (fclose(srcFile)) { diff --git a/programs/fileio_asyncio.c b/programs/fileio_asyncio.c index 3bca60a0820..38f9bc4f6a3 100644 --- a/programs/fileio_asyncio.c +++ b/programs/fileio_asyncio.c @@ -370,7 +370,7 @@ void AIO_WritePool_free(WritePoolCtx_t* ctx) { /* *********************************** * ReadPool implementation *************************************/ -static void ReadPool_releaseAllCompletedJobs(read_pool_ctx_t* ctx) { +static void AIO_ReadPool_releaseAllCompletedJobs(ReadPoolCtx_t* ctx) { int i; for(i=0; icompletedJobsCount; i++) { IOJob_t* job = (IOJob_t*) ctx->completedJobs[i]; @@ -379,8 +379,8 @@ static void ReadPool_releaseAllCompletedJobs(read_pool_ctx_t* ctx) { ctx->completedJobsCount = 0; } -static void ReadPool_addJobToCompleted(IOJob_t *job) { - read_pool_ctx_t *ctx = (read_pool_ctx_t *)job->ctx; +static void AIO_ReadPool_addJobToCompleted(IOJob_t *job) { + ReadPoolCtx_t *ctx = (ReadPoolCtx_t *)job->ctx; if(ctx->base.threadPool) ZSTD_pthread_mutex_lock(&ctx->base.ioJobsMutex); assert(ctx->completedJobsCount < MAX_IO_JOBS); @@ -391,11 +391,11 @@ static void ReadPool_addJobToCompleted(IOJob_t *job) { } } -/* ReadPool_findNextWaitingOffsetCompletedJob: +/* AIO_ReadPool_findNextWaitingOffsetCompletedJob: * Looks through the completed jobs for a job matching the waitingOnOffset and returns it, * if job wasn't found returns NULL. * IMPORTANT: assumes ioJobsMutex is locked. */ -static IOJob_t* ReadPool_findNextWaitingOffsetCompletedJob(read_pool_ctx_t *ctx) { +static IOJob_t* AIO_ReadPool_findNextWaitingOffsetCompletedJob(ReadPoolCtx_t *ctx) { IOJob_t *job = NULL; int i; for (i=0; icompletedJobsCount; i++) { @@ -408,21 +408,21 @@ static IOJob_t* ReadPool_findNextWaitingOffsetCompletedJob(read_pool_ctx_t *ctx) return NULL; } -/* ReadPool_getNextCompletedJob: +/* AIO_ReadPool_getNextCompletedJob: * Returns a completed IOJob_t for the next read in line based on waitingOnOffset and advances waitingOnOffset. * Would block. */ -static IOJob_t* ReadPool_getNextCompletedJob(read_pool_ctx_t *ctx) { +static IOJob_t* AIO_ReadPool_getNextCompletedJob(ReadPoolCtx_t *ctx) { IOJob_t *job = NULL; if(ctx->base.threadPool) ZSTD_pthread_mutex_lock(&ctx->base.ioJobsMutex); - job = ReadPool_findNextWaitingOffsetCompletedJob(ctx); + job = AIO_ReadPool_findNextWaitingOffsetCompletedJob(ctx); /* As long as we didn't find the job matching the next read, and we have some reads in flight continue waiting */ while (!job && (ctx->base.availableJobsCount + ctx->completedJobsCount < ctx->base.totalIoJobs)) { assert(ctx->base.threadPool != NULL); /* we shouldn't be here if we work in sync mode */ ZSTD_pthread_cond_wait(&ctx->jobCompletedCond, &ctx->base.ioJobsMutex); - job = ReadPool_findNextWaitingOffsetCompletedJob(ctx); + job = AIO_ReadPool_findNextWaitingOffsetCompletedJob(ctx); } if(job) { @@ -436,14 +436,14 @@ static IOJob_t* ReadPool_getNextCompletedJob(read_pool_ctx_t *ctx) { } -/* ReadPool_executeReadJob: +/* AIO_ReadPool_executeReadJob: * Executes a read job synchronously. Can be used as a function for a thread pool. */ -static void ReadPool_executeReadJob(void* opaque){ +static void AIO_ReadPool_executeReadJob(void* opaque){ IOJob_t* job = (IOJob_t*) opaque; - read_pool_ctx_t* ctx = (read_pool_ctx_t *)job->ctx; + ReadPoolCtx_t* ctx = (ReadPoolCtx_t *)job->ctx; if(ctx->reachedEof) { job->usedBufferSize = 0; - ReadPool_addJobToCompleted(job); + AIO_ReadPool_addJobToCompleted(job); return; } job->usedBufferSize = fread(job->buffer, 1, job->bufferSize, job->file); @@ -455,47 +455,47 @@ static void ReadPool_executeReadJob(void* opaque){ } else EXM_THROW(37, "Unexpected short read"); } - ReadPool_addJobToCompleted(job); + AIO_ReadPool_addJobToCompleted(job); } -static void ReadPool_enqueueRead(read_pool_ctx_t *ctx) { +static void AIO_ReadPool_enqueueRead(ReadPoolCtx_t *ctx) { IOJob_t *job = AIO_IOPool_acquireJob(&ctx->base); job->offset = ctx->nextReadOffset; ctx->nextReadOffset += job->bufferSize; AIO_IOPool_enqueueJob(job); } -static void ReadPool_startReading(read_pool_ctx_t *ctx) { +static void AIO_ReadPool_startReading(ReadPoolCtx_t *ctx) { int i; for (i = 0; i < ctx->base.availableJobsCount; i++) { - ReadPool_enqueueRead(ctx); + AIO_ReadPool_enqueueRead(ctx); } } -/* ReadPool_setFile: +/* AIO_ReadPool_setFile: * Sets the source file for future read in the pool. Initiates reading immediately if file is not NULL. * Waits for all current enqueued tasks to complete if a previous file was set. */ -void ReadPool_setFile(read_pool_ctx_t *ctx, FILE* file) { +void AIO_ReadPool_setFile(ReadPoolCtx_t *ctx, FILE* file) { assert(ctx!=NULL); AIO_IOPool_join(&ctx->base); - ReadPool_releaseAllCompletedJobs(ctx); + AIO_ReadPool_releaseAllCompletedJobs(ctx); AIO_IOPool_setFile(&ctx->base, file); ctx->nextReadOffset = 0; ctx->waitingOnOffset = 0; ctx->srcBuffer = ctx->srcBufferBase; ctx->reachedEof = 0; if(file != NULL) - ReadPool_startReading(ctx); + AIO_ReadPool_startReading(ctx); } -/* ReadPool_create: +/* AIO_ReadPool_create: * Allocates and sets and a new readPool including its included jobs. * bufferSize should be set to the maximal buffer we want to read at a time, will also be used * as our basic read size. */ -read_pool_ctx_t* ReadPool_create(FIO_prefs_t* const prefs, size_t bufferSize) { - read_pool_ctx_t* ctx = (read_pool_ctx_t*) malloc(sizeof(read_pool_ctx_t)); +ReadPoolCtx_t* AIO_ReadPool_create(FIO_prefs_t* const prefs, size_t bufferSize) { + ReadPoolCtx_t* ctx = (ReadPoolCtx_t*) malloc(sizeof(ReadPoolCtx_t)); if(!ctx) EXM_THROW(100, "Allocation error : not enough memory"); - AIO_IOPool_init(&ctx->base, prefs, ReadPool_executeReadJob, bufferSize); + AIO_IOPool_init(&ctx->base, prefs, AIO_ReadPool_executeReadJob, bufferSize); ctx->srcBufferBaseSize = 2 * bufferSize; ctx->srcBufferBase = (U8*) malloc(ctx->srcBufferBaseSize); @@ -510,11 +510,11 @@ read_pool_ctx_t* ReadPool_create(FIO_prefs_t* const prefs, size_t bufferSize) { return ctx; } -/* ReadPool_free: +/* AIO_ReadPool_free: * Frees and releases a readPool and its resources. Closes source file. */ -void ReadPool_free(read_pool_ctx_t* ctx) { - if(ReadPool_getFile(ctx)) - ReadPool_closeFile(ctx); +void AIO_ReadPool_free(ReadPoolCtx_t* ctx) { + if(AIO_ReadPool_getFile(ctx)) + AIO_ReadPool_closeFile(ctx); if(ctx->base.threadPool) ZSTD_pthread_cond_destroy(&ctx->jobCompletedCond); AIO_IOPool_destroy(&ctx->base); @@ -522,28 +522,28 @@ void ReadPool_free(read_pool_ctx_t* ctx) { free(ctx); } -/* ReadPool_consumeBytes: +/* AIO_ReadPool_consumeBytes: * Consumes byes from srcBuffer's beginning and updates srcBufferLoaded accordingly. */ -void ReadPool_consumeBytes(read_pool_ctx_t *ctx, size_t n) { +void AIO_ReadPool_consumeBytes(ReadPoolCtx_t *ctx, size_t n) { assert(n <= ctx->srcBufferLoaded); assert(ctx->srcBuffer + n <= ctx->srcBufferBase + ctx->srcBufferBaseSize); ctx->srcBufferLoaded -= n; ctx->srcBuffer += n; } -/* ReadPool_fillBuffer: +/* AIO_ReadPool_fillBuffer: * Makes sure buffer has at least n bytes loaded (as long as n is not bigger than the initalized bufferSize). * Returns if srcBuffer has at least n bytes loaded or if we've reached the end of the file. * Return value is the number of bytes added to the buffer. * Note that srcBuffer might have up to 2 times bufferSize bytes. */ -size_t ReadPool_fillBuffer(read_pool_ctx_t *ctx, size_t n) { +size_t AIO_ReadPool_fillBuffer(ReadPoolCtx_t *ctx, size_t n) { IOJob_t *job; size_t srcBufferOffsetFromBase; size_t srcBufferRemainingSpace; size_t bytesRead = 0; assert(n <= ctx->srcBufferBaseSize/2); while (ctx->srcBufferLoaded < n) { - job = ReadPool_getNextCompletedJob(ctx); + job = AIO_ReadPool_getNextCompletedJob(ctx); if(job == NULL) break; srcBufferOffsetFromBase = ctx->srcBuffer - ctx->srcBufferBase; @@ -560,28 +560,28 @@ size_t ReadPool_fillBuffer(read_pool_ctx_t *ctx, size_t n) { break; } AIO_IOPool_releaseIoJob(job); - ReadPool_enqueueRead(ctx); + AIO_ReadPool_enqueueRead(ctx); } return bytesRead; } -/* ReadPool_consumeAndRefill: +/* AIO_ReadPool_consumeAndRefill: * Consumes the current buffer and refills it with bufferSize bytes. */ -size_t ReadPool_consumeAndRefill(read_pool_ctx_t *ctx) { - ReadPool_consumeBytes(ctx, ctx->srcBufferLoaded); - return ReadPool_fillBuffer(ctx, ctx->srcBufferBaseSize/2); +size_t AIO_ReadPool_consumeAndRefill(ReadPoolCtx_t *ctx) { + AIO_ReadPool_consumeBytes(ctx, ctx->srcBufferLoaded); + return AIO_ReadPool_fillBuffer(ctx, ctx->srcBufferBaseSize/2); } -/* ReadPool_getFile: +/* AIO_ReadPool_getFile: * Returns the current file set for the read pool. */ -FILE* ReadPool_getFile(read_pool_ctx_t *ctx) { +FILE* AIO_ReadPool_getFile(ReadPoolCtx_t *ctx) { return AIO_IOPool_getFile(&ctx->base); } -/* ReadPool_closeFile: +/* AIO_ReadPool_closeFile: * Closes the current set file. Waits for all current enqueued tasks to complete and resets state. */ -int ReadPool_closeFile(read_pool_ctx_t *ctx) { - FILE* file = ReadPool_getFile(ctx); - ReadPool_setFile(ctx, NULL); +int AIO_ReadPool_closeFile(ReadPoolCtx_t *ctx) { + FILE* file = AIO_ReadPool_getFile(ctx); + AIO_ReadPool_setFile(ctx, NULL); return fclose(file); } diff --git a/programs/fileio_asyncio.h b/programs/fileio_asyncio.h index 77670624470..e7079a8a38e 100644 --- a/programs/fileio_asyncio.h +++ b/programs/fileio_asyncio.h @@ -63,7 +63,7 @@ typedef struct { void* completedJobs[MAX_IO_JOBS]; int completedJobsCount; ZSTD_pthread_cond_t jobCompletedCond; -} read_pool_ctx_t; +} ReadPoolCtx_t; typedef struct { IOPoolCtx_t base; @@ -128,43 +128,43 @@ WritePoolCtx_t* AIO_WritePool_create(FIO_prefs_t* const prefs, size_t bufferSize * Frees and releases a writePool and its resources. Closes destination file. */ void AIO_WritePool_free(WritePoolCtx_t* ctx); -/* ReadPool_create: +/* AIO_ReadPool_create: * Allocates and sets and a new readPool including its included jobs. * bufferSize should be set to the maximal buffer we want to read at a time, will also be used * as our basic read size. */ -read_pool_ctx_t* ReadPool_create(FIO_prefs_t* const prefs, size_t bufferSize); +ReadPoolCtx_t* AIO_ReadPool_create(FIO_prefs_t* const prefs, size_t bufferSize); -/* ReadPool_free: +/* AIO_ReadPool_free: * Frees and releases a readPool and its resources. Closes source file. */ -void ReadPool_free(read_pool_ctx_t* ctx); +void AIO_ReadPool_free(ReadPoolCtx_t* ctx); -/* ReadPool_consumeBytes: +/* AIO_ReadPool_consumeBytes: * Consumes byes from srcBuffer's beginning and updates srcBufferLoaded accordingly. */ -void ReadPool_consumeBytes(read_pool_ctx_t *ctx, size_t n); +void AIO_ReadPool_consumeBytes(ReadPoolCtx_t *ctx, size_t n); -/* ReadPool_fillBuffer: +/* AIO_ReadPool_fillBuffer: * Makes sure buffer has at least n bytes loaded (as long as n is not bigger than the initalized bufferSize). * Returns if srcBuffer has at least n bytes loaded or if we've reached the end of the file. * Return value is the number of bytes added to the buffer. * Note that srcBuffer might have up to 2 times bufferSize bytes. */ -size_t ReadPool_fillBuffer(read_pool_ctx_t *ctx, size_t n); +size_t AIO_ReadPool_fillBuffer(ReadPoolCtx_t *ctx, size_t n); -/* ReadPool_consumeAndRefill: +/* AIO_ReadPool_consumeAndRefill: * Consumes the current buffer and refills it with bufferSize bytes. */ -size_t ReadPool_consumeAndRefill(read_pool_ctx_t *ctx); +size_t AIO_ReadPool_consumeAndRefill(ReadPoolCtx_t *ctx); -/* ReadPool_setFile: +/* AIO_ReadPool_setFile: * Sets the source file for future read in the pool. Initiates reading immediately if file is not NULL. * Waits for all current enqueued tasks to complete if a previous file was set. */ -void ReadPool_setFile(read_pool_ctx_t *ctx, FILE* file); +void AIO_ReadPool_setFile(ReadPoolCtx_t *ctx, FILE* file); -/* ReadPool_getFile: +/* AIO_ReadPool_getFile: * Returns the current file set for the read pool. */ -FILE* ReadPool_getFile(read_pool_ctx_t *ctx); +FILE* AIO_ReadPool_getFile(ReadPoolCtx_t *ctx); -/* ReadPool_closeFile: +/* AIO_ReadPool_closeFile: * Closes the current set file. Waits for all current enqueued tasks to complete and resets state. */ -int ReadPool_closeFile(read_pool_ctx_t *ctx); +int AIO_ReadPool_closeFile(ReadPoolCtx_t *ctx); #if defined (__cplusplus) } From 2cbc104493df93f3904185935d17d4ac6f6cff5f Mon Sep 17 00:00:00 2001 From: Yonatan Komornik Date: Mon, 24 Jan 2022 14:55:33 -0800 Subject: [PATCH 09/23] Small cosmetic changes --- programs/fileio.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index b246d577c1a..288c494ea8b 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -1494,7 +1494,7 @@ FIO_compressFilename_internal(FIO_ctx_t* const fCtx, #else (void)compressionLevel; EXM_THROW(20, "zstd: %s: file cannot be compressed as xz/lzma (zstd compiled without ZSTD_LZMACOMPRESS) -- ignored \n", - srcFileName); + srcFileName); #endif break; @@ -1519,13 +1519,13 @@ FIO_compressFilename_internal(FIO_ctx_t* const fCtx, UTIL_HumanReadableSize_t hr_isize = UTIL_makeHumanReadableSize((U64) readsize); UTIL_HumanReadableSize_t hr_osize = UTIL_makeHumanReadableSize((U64) compressedfilesize); if (readsize == 0) { - DISPLAYLEVEL(2,"%-20s : (%6.*f%4s => %6.*f%4s, %s) \n", + DISPLAYLEVEL(2,"%-20s : (%6.*f%s => %6.*f%s, %s) \n", srcFileName, hr_isize.precision, hr_isize.value, hr_isize.suffix, hr_osize.precision, hr_osize.value, hr_osize.suffix, dstFileName); } else { - DISPLAYLEVEL(2,"%-20s :%6.2f%% (%6.*f%4s => %6.*f%4s, %s) \n", + DISPLAYLEVEL(2,"%-20s :%6.2f%% (%6.*f%s => %6.*f%s, %s) \n", srcFileName, (double)compressedfilesize / (double)readsize * 100, hr_isize.precision, hr_isize.value, hr_isize.suffix, @@ -1910,7 +1910,7 @@ static dRess_t FIO_createDResources(FIO_prefs_t* const prefs, const char* dictFi /* Allocation */ ress.dctx = ZSTD_createDStream(); if (ress.dctx==NULL) - EXM_THROW(60, "Error: %s : can't create ZSTD_DStream", strerror(errno)); + EXM_THROW(60, "Error: %s : can't create ZSTD_DStream", strerror(errno)); CHECK( ZSTD_DCtx_setMaxWindowSize(ress.dctx, prefs->memLimit) ); CHECK( ZSTD_DCtx_setParameter(ress.dctx, ZSTD_d_forceIgnoreChecksum, !prefs->checksumFlag)); From 512e5a35605f504416fff99136d089f23bca267e Mon Sep 17 00:00:00 2001 From: Yonatan Komornik Date: Mon, 24 Jan 2022 16:28:41 -0800 Subject: [PATCH 10/23] CR fixes --- programs/fileio_asyncio.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/programs/fileio_asyncio.c b/programs/fileio_asyncio.c index 38f9bc4f6a3..374a721ccc7 100644 --- a/programs/fileio_asyncio.c +++ b/programs/fileio_asyncio.c @@ -391,13 +391,17 @@ static void AIO_ReadPool_addJobToCompleted(IOJob_t *job) { } } -/* AIO_ReadPool_findNextWaitingOffsetCompletedJob: +/* AIO_ReadPool_findNextWaitingOffsetCompletedJob_locked: * Looks through the completed jobs for a job matching the waitingOnOffset and returns it, * if job wasn't found returns NULL. * IMPORTANT: assumes ioJobsMutex is locked. */ -static IOJob_t* AIO_ReadPool_findNextWaitingOffsetCompletedJob(ReadPoolCtx_t *ctx) { +static IOJob_t* AIO_ReadPool_findNextWaitingOffsetCompletedJob_locked(ReadPoolCtx_t *ctx) { IOJob_t *job = NULL; int i; + /* This implementation goes through all completed jobs and looks for the one matching the next offset. + * While not strictly needed for a single threaded reader implementation (as in such a case we could expect + * reads to be completed in order) this implementation was chosen as it better fits other asyncio + * interfaces (such as io_uring) that do not provide promises regarding order of completion. */ for (i=0; icompletedJobsCount; i++) { job = (IOJob_t *) ctx->completedJobs[i]; if (job->offset == ctx->waitingOnOffset) { @@ -416,13 +420,13 @@ static IOJob_t* AIO_ReadPool_getNextCompletedJob(ReadPoolCtx_t *ctx) { if(ctx->base.threadPool) ZSTD_pthread_mutex_lock(&ctx->base.ioJobsMutex); - job = AIO_ReadPool_findNextWaitingOffsetCompletedJob(ctx); + job = AIO_ReadPool_findNextWaitingOffsetCompletedJob_locked(ctx); /* As long as we didn't find the job matching the next read, and we have some reads in flight continue waiting */ while (!job && (ctx->base.availableJobsCount + ctx->completedJobsCount < ctx->base.totalIoJobs)) { assert(ctx->base.threadPool != NULL); /* we shouldn't be here if we work in sync mode */ ZSTD_pthread_cond_wait(&ctx->jobCompletedCond, &ctx->base.ioJobsMutex); - job = AIO_ReadPool_findNextWaitingOffsetCompletedJob(ctx); + job = AIO_ReadPool_findNextWaitingOffsetCompletedJob_locked(ctx); } if(job) { @@ -452,8 +456,9 @@ static void AIO_ReadPool_executeReadJob(void* opaque){ EXM_THROW(37, "Read error"); } else if(feof(job->file)) { ctx->reachedEof = 1; - } else - EXM_THROW(37, "Unexpected short read"); + } else { + EXM_THROW(37, "Unexpected short read"); + } } AIO_ReadPool_addJobToCompleted(job); } From f1715ef5d97f2b4fbf435615f31b68d46b4b602b Mon Sep 17 00:00:00 2001 From: Yonatan Komornik Date: Mon, 24 Jan 2022 16:41:48 -0800 Subject: [PATCH 11/23] CR fixes - disabled sparse write for compression --- programs/zstdcli.c | 1 + 1 file changed, 1 insertion(+) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index fd563e1c24d..53f0eca68e3 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -1445,6 +1445,7 @@ int main(int argCount, const char* argv[]) FIO_setTargetCBlockSize(prefs, targetCBlockSize); FIO_setSrcSizeHint(prefs, srcSizeHint); FIO_setLiteralCompressionMode(prefs, literalCompressionMode); + FIO_setSparseWrite(prefs, 0); if (adaptMin > cLevel) cLevel = adaptMin; if (adaptMax < cLevel) cLevel = adaptMax; From 4cac292bdd5ec2d77be14e64bd57d036e75403a3 Mon Sep 17 00:00:00 2001 From: Yonatan Komornik Date: Tue, 25 Jan 2022 17:39:02 -0800 Subject: [PATCH 12/23] Asyncio Compression: significantly reduced the number of memcpys --- programs/fileio.c | 5 +- programs/fileio_asyncio.c | 121 ++++++++++++++++++++++---------------- programs/fileio_asyncio.h | 10 +++- 3 files changed, 78 insertions(+), 58 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index 288c494ea8b..fac9384968f 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -1151,7 +1151,7 @@ FIO_compressLz4Frame(cRess_t* ress, memset(&prefs, 0, sizeof(prefs)); - assert(blockSize <= ress->readCtx->srcBufferBaseSize); + assert(blockSize <= ress->readCtx->base.jobBufferSize); prefs.autoFlush = 1; prefs.compressionLevel = compressionLevel; @@ -2011,8 +2011,7 @@ FIO_decompressZstdFrame(FIO_ctx_t* const fCtx, dRess_t* ress, ZSTD_DCtx_reset(ress->dctx, ZSTD_reset_session_only); /* Header loading : ensures ZSTD_getFrameHeader() will succeed */ - if (ress->readCtx->srcBufferLoaded < ZSTD_FRAMEHEADERSIZE_MAX) - AIO_ReadPool_fillBuffer(ress->readCtx, ZSTD_FRAMEHEADERSIZE_MAX); + AIO_ReadPool_fillBuffer(ress->readCtx, ZSTD_FRAMEHEADERSIZE_MAX); /* Main decompression Loop */ while (1) { diff --git a/programs/fileio_asyncio.c b/programs/fileio_asyncio.c index 374a721ccc7..b6c6240bcf6 100644 --- a/programs/fileio_asyncio.c +++ b/programs/fileio_asyncio.c @@ -174,11 +174,12 @@ static void AIO_IOPool_init(IOPoolCtx_t *ctx, FIO_prefs_t* const prefs, POOL_fun AIO_IOPool_createThreadPool(ctx, prefs); ctx->prefs = prefs; ctx->poolFunction = poolFunction; - ctx->totalIoJobs = ctx->threadPool ? MAX_IO_JOBS : 1; + ctx->totalIoJobs = ctx->threadPool ? MAX_IO_JOBS : 2; ctx->availableJobsCount = ctx->totalIoJobs; for(i=0; i < ctx->availableJobsCount; i++) { ctx->availableJobs[i] = AIO_IOPool_createIoJob(ctx, bufferSize); } + ctx->jobBufferSize = bufferSize; ctx->file = NULL; } @@ -187,15 +188,12 @@ static void AIO_IOPool_init(IOPoolCtx_t *ctx, FIO_prefs_t* const prefs, POOL_fun * Releases an acquired job back to the pool. Doesn't execute the job. */ static void AIO_IOPool_releaseIoJob(IOJob_t *job) { IOPoolCtx_t *ctx = (IOPoolCtx_t *) job->ctx; - if(ctx->threadPool) { + if(ctx->threadPool) ZSTD_pthread_mutex_lock(&ctx->ioJobsMutex); - assert(ctx->availableJobsCount < MAX_IO_JOBS); - ctx->availableJobs[ctx->availableJobsCount++] = job; + assert(ctx->availableJobsCount < ctx->totalIoJobs); + ctx->availableJobs[ctx->availableJobsCount++] = job; + if(ctx->threadPool) ZSTD_pthread_mutex_unlock(&ctx->ioJobsMutex); - } else { - assert(ctx->availableJobsCount == 0); - ctx->availableJobsCount++; - } } /* AIO_IOPool_join: @@ -230,16 +228,12 @@ static void AIO_IOPool_destroy(IOPoolCtx_t* ctx) { static IOJob_t* AIO_IOPool_acquireJob(IOPoolCtx_t *ctx) { IOJob_t *job; assert(ctx->file != NULL || ctx->prefs->testMode); - if(ctx->threadPool) { + if(ctx->threadPool) ZSTD_pthread_mutex_lock(&ctx->ioJobsMutex); - assert(ctx->availableJobsCount > 0); - job = (IOJob_t*) ctx->availableJobs[--ctx->availableJobsCount]; + assert(ctx->availableJobsCount > 0); + job = (IOJob_t*) ctx->availableJobs[--ctx->availableJobsCount]; + if(ctx->threadPool) ZSTD_pthread_mutex_unlock(&ctx->ioJobsMutex); - } else { - assert(ctx->availableJobsCount == 1); - ctx->availableJobsCount--; - job = (IOJob_t*)ctx->availableJobs[0]; - } job->usedBufferSize = 0; job->file = ctx->file; job->offset = 0; @@ -412,18 +406,25 @@ static IOJob_t* AIO_ReadPool_findNextWaitingOffsetCompletedJob_locked(ReadPoolCt return NULL; } +/* AIO_ReadPool_numReadsInFlight: + * Returns the number of IO read jobs currrently in flight. */ +static size_t AIO_ReadPool_numReadsInFlight(ReadPoolCtx_t *ctx) { + const size_t jobsHeld = (ctx->currentJobHeld==NULL ? 0 : 1); + return ctx->base.totalIoJobs - (ctx->base.availableJobsCount + ctx->completedJobsCount + jobsHeld); +} + /* AIO_ReadPool_getNextCompletedJob: * Returns a completed IOJob_t for the next read in line based on waitingOnOffset and advances waitingOnOffset. * Would block. */ static IOJob_t* AIO_ReadPool_getNextCompletedJob(ReadPoolCtx_t *ctx) { IOJob_t *job = NULL; - if(ctx->base.threadPool) + if (ctx->base.threadPool) ZSTD_pthread_mutex_lock(&ctx->base.ioJobsMutex); job = AIO_ReadPool_findNextWaitingOffsetCompletedJob_locked(ctx); /* As long as we didn't find the job matching the next read, and we have some reads in flight continue waiting */ - while (!job && (ctx->base.availableJobsCount + ctx->completedJobsCount < ctx->base.totalIoJobs)) { + while (!job && (AIO_ReadPool_numReadsInFlight(ctx) > 0)) { assert(ctx->base.threadPool != NULL); /* we shouldn't be here if we work in sync mode */ ZSTD_pthread_cond_wait(&ctx->jobCompletedCond, &ctx->base.ioJobsMutex); job = AIO_ReadPool_findNextWaitingOffsetCompletedJob_locked(ctx); @@ -434,7 +435,7 @@ static IOJob_t* AIO_ReadPool_getNextCompletedJob(ReadPoolCtx_t *ctx) { ctx->waitingOnOffset += job->usedBufferSize; } - if(ctx->base.threadPool) + if (ctx->base.threadPool) ZSTD_pthread_mutex_unlock(&ctx->base.ioJobsMutex); return job; } @@ -484,10 +485,15 @@ void AIO_ReadPool_setFile(ReadPoolCtx_t *ctx, FILE* file) { assert(ctx!=NULL); AIO_IOPool_join(&ctx->base); AIO_ReadPool_releaseAllCompletedJobs(ctx); + if (ctx->currentJobHeld) { + AIO_IOPool_releaseIoJob((IOJob_t *)ctx->currentJobHeld); + ctx->currentJobHeld = NULL; + } AIO_IOPool_setFile(&ctx->base, file); ctx->nextReadOffset = 0; ctx->waitingOnOffset = 0; - ctx->srcBuffer = ctx->srcBufferBase; + ctx->srcBuffer = ctx->coalesceBuffer; + ctx->srcBufferLoaded = 0; ctx->reachedEof = 0; if(file != NULL) AIO_ReadPool_startReading(ctx); @@ -502,11 +508,11 @@ ReadPoolCtx_t* AIO_ReadPool_create(FIO_prefs_t* const prefs, size_t bufferSize) if(!ctx) EXM_THROW(100, "Allocation error : not enough memory"); AIO_IOPool_init(&ctx->base, prefs, AIO_ReadPool_executeReadJob, bufferSize); - ctx->srcBufferBaseSize = 2 * bufferSize; - ctx->srcBufferBase = (U8*) malloc(ctx->srcBufferBaseSize); - ctx->srcBuffer = ctx->srcBufferBase; + ctx->coalesceBuffer = (U8*) malloc(bufferSize * 2); + ctx->srcBuffer = ctx->coalesceBuffer; ctx->srcBufferLoaded = 0; ctx->completedJobsCount = 0; + ctx->currentJobHeld = NULL; if(ctx->base.threadPool) if (ZSTD_pthread_cond_init(&ctx->jobCompletedCond, NULL)) @@ -523,7 +529,7 @@ void AIO_ReadPool_free(ReadPoolCtx_t* ctx) { if(ctx->base.threadPool) ZSTD_pthread_cond_destroy(&ctx->jobCompletedCond); AIO_IOPool_destroy(&ctx->base); - free(ctx->srcBufferBase); + free(ctx->coalesceBuffer); free(ctx); } @@ -531,50 +537,61 @@ void AIO_ReadPool_free(ReadPoolCtx_t* ctx) { * Consumes byes from srcBuffer's beginning and updates srcBufferLoaded accordingly. */ void AIO_ReadPool_consumeBytes(ReadPoolCtx_t *ctx, size_t n) { assert(n <= ctx->srcBufferLoaded); - assert(ctx->srcBuffer + n <= ctx->srcBufferBase + ctx->srcBufferBaseSize); ctx->srcBufferLoaded -= n; ctx->srcBuffer += n; } +/* AIO_ReadPool_releaseCurrentlyHeldAndGetNext: + * Release the current held job and get the next one, returns NULL if no next job available. */ +static IOJob_t* AIO_ReadPool_releaseCurrentHeldAndGetNext(ReadPoolCtx_t *ctx) { + if (ctx->currentJobHeld) { + AIO_IOPool_releaseIoJob((IOJob_t *)ctx->currentJobHeld); + ctx->currentJobHeld = NULL; + AIO_ReadPool_enqueueRead(ctx); + } + ctx->currentJobHeld = AIO_ReadPool_getNextCompletedJob(ctx); + return (IOJob_t*) ctx->currentJobHeld; +} + /* AIO_ReadPool_fillBuffer: - * Makes sure buffer has at least n bytes loaded (as long as n is not bigger than the initalized bufferSize). + * Makes sure buffer has at least n bytes loaded (n can't be bigger than jobBufferSize). * Returns if srcBuffer has at least n bytes loaded or if we've reached the end of the file. * Return value is the number of bytes added to the buffer. - * Note that srcBuffer might have up to 2 times bufferSize bytes. */ + * Note that srcBuffer might have up to 2 times jobBufferSize bytes. */ size_t AIO_ReadPool_fillBuffer(ReadPoolCtx_t *ctx, size_t n) { IOJob_t *job; - size_t srcBufferOffsetFromBase; - size_t srcBufferRemainingSpace; - size_t bytesRead = 0; - assert(n <= ctx->srcBufferBaseSize/2); - while (ctx->srcBufferLoaded < n) { - job = AIO_ReadPool_getNextCompletedJob(ctx); - if(job == NULL) - break; - srcBufferOffsetFromBase = ctx->srcBuffer - ctx->srcBufferBase; - srcBufferRemainingSpace = ctx->srcBufferBaseSize - (srcBufferOffsetFromBase + ctx->srcBufferLoaded); - if(job->usedBufferSize > srcBufferRemainingSpace) { - memmove(ctx->srcBufferBase, ctx->srcBuffer, ctx->srcBufferLoaded); - ctx->srcBuffer = ctx->srcBufferBase; - } - memcpy(ctx->srcBuffer + ctx->srcBufferLoaded, job->buffer, job->usedBufferSize); - bytesRead += job->usedBufferSize; - ctx->srcBufferLoaded += job->usedBufferSize; - if(job->usedBufferSize < job->bufferSize) { - AIO_IOPool_releaseIoJob(job); - break; - } - AIO_IOPool_releaseIoJob(job); - AIO_ReadPool_enqueueRead(ctx); + int useCoalesce = 0; + assert(n <= ctx->base.jobBufferSize); + + /* We are good, don't read anything */ + if (ctx->srcBufferLoaded >= n) + return 0; + + /* We still have bytes loaded, but enough to satisfy caller. We need to get the next job + * and coalesce the remaining bytes with the next job's buffer */ + if (ctx->srcBufferLoaded > 0) { + useCoalesce = 1; + memcpy(ctx->coalesceBuffer, ctx->srcBuffer, ctx->srcBufferLoaded); + ctx->srcBuffer = ctx->coalesceBuffer; } - return bytesRead; + + /* Read the next chunk */ + job = AIO_ReadPool_releaseCurrentHeldAndGetNext(ctx); + if(!job) + return 0; + if(useCoalesce) + memcpy(ctx->coalesceBuffer + ctx->srcBufferLoaded, job->buffer, job->usedBufferSize); + else + ctx->srcBuffer = (U8*) job->buffer; + ctx->srcBufferLoaded += job->usedBufferSize; + return job->usedBufferSize; } /* AIO_ReadPool_consumeAndRefill: * Consumes the current buffer and refills it with bufferSize bytes. */ size_t AIO_ReadPool_consumeAndRefill(ReadPoolCtx_t *ctx) { AIO_ReadPool_consumeBytes(ctx, ctx->srcBufferLoaded); - return AIO_ReadPool_fillBuffer(ctx, ctx->srcBufferBaseSize/2); + return AIO_ReadPool_fillBuffer(ctx, ctx->base.jobBufferSize); } /* AIO_ReadPool_getFile: diff --git a/programs/fileio_asyncio.h b/programs/fileio_asyncio.h index e7079a8a38e..1b034c37fd8 100644 --- a/programs/fileio_asyncio.h +++ b/programs/fileio_asyncio.h @@ -39,6 +39,7 @@ typedef struct { ZSTD_pthread_mutex_t ioJobsMutex; void* availableJobs[MAX_IO_JOBS]; int availableJobsCount; + size_t jobBufferSize; } IOPoolCtx_t; typedef struct { @@ -49,9 +50,12 @@ typedef struct { U64 nextReadOffset; U64 waitingOnOffset; - /* Bases buffer, shouldn't be accessed from outside ot utility functions. */ - U8 *srcBufferBase; - size_t srcBufferBaseSize; + /* We may hold an IOJob object as needed if we actively expose its buffer. */ + void *currentJobHeld; + + /* Coalesce buffer is used to join two buffers in case where we need to read more bytes than left in + * the first of them. Shouldn't be accessed from outside ot utility functions. */ + U8 *coalesceBuffer; /* Read buffer can be used by consumer code, take care when copying this pointer aside as it might * change when consuming / refilling buffer. */ From a5de44651a8b6f296ebbcf4a7e349685766d2b4c Mon Sep 17 00:00:00 2001 From: Yonatan Komornik Date: Tue, 25 Jan 2022 18:42:24 -0800 Subject: [PATCH 13/23] Asyncio Compression: fixed write error messages --- programs/fileio_asyncio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/programs/fileio_asyncio.c b/programs/fileio_asyncio.c index b6c6240bcf6..5f4eb42d63f 100644 --- a/programs/fileio_asyncio.c +++ b/programs/fileio_asyncio.c @@ -46,7 +46,7 @@ AIO_fwriteSparse(FILE* file, if (!prefs->sparseFileSupport) { /* normal write */ size_t const sizeCheck = fwrite(buffer, 1, bufferSize, file); if (sizeCheck != bufferSize) - EXM_THROW(70, "Write error : cannot write decoded block : %s", + EXM_THROW(70, "Write error : cannot write block : %s", strerror(errno)); return 0; } @@ -78,7 +78,7 @@ AIO_fwriteSparse(FILE* file, storedSkips = 0; /* write the rest */ if (fwrite(ptrT + nb0T, sizeof(size_t), nbNon0ST, file) != nbNon0ST) - EXM_THROW(93, "Write error : cannot write decoded block : %s", + EXM_THROW(93, "Write error : cannot write block : %s", strerror(errno)); } ptrT += seg0SizeT; From 0f5f6eddaaa4a0bccc9a0b2452be3764628e9f82 Mon Sep 17 00:00:00 2001 From: Yonatan Komornik Date: Wed, 26 Jan 2022 01:10:29 -0800 Subject: [PATCH 14/23] Asyncio Compression: CR fixes --- programs/fileio.c | 2 +- programs/fileio_asyncio.c | 86 +++++++++++++++++++-------------------- programs/fileio_asyncio.h | 10 ++--- tests/playTests.sh | 12 +++--- 4 files changed, 55 insertions(+), 55 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index fac9384968f..a25eb2af730 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -1143,7 +1143,7 @@ FIO_compressLz4Frame(cRess_t* ress, LZ4F_preferences_t prefs; LZ4F_compressionContext_t ctx; - IOJob_t *writeJob =AIO_WritePool_acquireJob(ress->writeCtx); + IOJob_t* writeJob = AIO_WritePool_acquireJob(ress->writeCtx); LZ4F_errorCode_t const errorCode = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION); if (LZ4F_isError(errorCode)) diff --git a/programs/fileio_asyncio.c b/programs/fileio_asyncio.c index 5f4eb42d63f..2d8b8a138b2 100644 --- a/programs/fileio_asyncio.c +++ b/programs/fileio_asyncio.c @@ -134,10 +134,8 @@ AIO_fwriteSparseEnd(const FIO_prefs_t* const prefs, FILE* file, unsigned storedS *************************************/ static IOJob_t *AIO_IOPool_createIoJob(IOPoolCtx_t *ctx, size_t bufferSize) { - void *buffer; - IOJob_t *job; - job = (IOJob_t*) malloc(sizeof(IOJob_t)); - buffer = malloc(bufferSize); + IOJob_t* const job = (IOJob_t*) malloc(sizeof(IOJob_t)); + void* const buffer = malloc(bufferSize); if(!job || !buffer) EXM_THROW(101, "Allocation error : not enough memory"); job->buffer = buffer; @@ -153,7 +151,7 @@ static IOJob_t *AIO_IOPool_createIoJob(IOPoolCtx_t *ctx, size_t bufferSize) { /* AIO_IOPool_createThreadPool: * Creates a thread pool and a mutex for threaded IO pool. * Displays warning if asyncio is requested but MT isn't available. */ -static void AIO_IOPool_createThreadPool(IOPoolCtx_t *ctx, const FIO_prefs_t *prefs) { +static void AIO_IOPool_createThreadPool(IOPoolCtx_t* ctx, const FIO_prefs_t* prefs) { ctx->threadPool = NULL; if(prefs->asyncIO) { if (ZSTD_pthread_mutex_init(&ctx->ioJobsMutex, NULL)) @@ -169,7 +167,7 @@ static void AIO_IOPool_createThreadPool(IOPoolCtx_t *ctx, const FIO_prefs_t *pre /* AIO_IOPool_init: * Allocates and sets and a new write pool including its included availableJobs. */ -static void AIO_IOPool_init(IOPoolCtx_t *ctx, FIO_prefs_t* const prefs, POOL_function poolFunction, size_t bufferSize) { +static void AIO_IOPool_init(IOPoolCtx_t* ctx, const FIO_prefs_t* prefs, POOL_function poolFunction, size_t bufferSize) { int i; AIO_IOPool_createThreadPool(ctx, prefs); ctx->prefs = prefs; @@ -186,8 +184,8 @@ static void AIO_IOPool_init(IOPoolCtx_t *ctx, FIO_prefs_t* const prefs, POOL_fun /* AIO_IOPool_releaseIoJob: * Releases an acquired job back to the pool. Doesn't execute the job. */ -static void AIO_IOPool_releaseIoJob(IOJob_t *job) { - IOPoolCtx_t *ctx = (IOPoolCtx_t *) job->ctx; +static void AIO_IOPool_releaseIoJob(IOJob_t* job) { + IOPoolCtx_t* const ctx = (IOPoolCtx_t *) job->ctx; if(ctx->threadPool) ZSTD_pthread_mutex_lock(&ctx->ioJobsMutex); assert(ctx->availableJobsCount < ctx->totalIoJobs); @@ -225,7 +223,7 @@ static void AIO_IOPool_destroy(IOPoolCtx_t* ctx) { /* AIO_IOPool_acquireJob: * Returns an available io job to be used for a future io. */ -static IOJob_t* AIO_IOPool_acquireJob(IOPoolCtx_t *ctx) { +static IOJob_t* AIO_IOPool_acquireJob(IOPoolCtx_t* ctx) { IOJob_t *job; assert(ctx->file != NULL || ctx->prefs->testMode); if(ctx->threadPool) @@ -245,22 +243,22 @@ static IOJob_t* AIO_IOPool_acquireJob(IOPoolCtx_t *ctx) { * Sets the destination file for future files in the pool. * Requires completion of all queues write jobs and release of all otherwise acquired jobs. * Also requires ending of sparse write if a previous file was used in sparse mode. */ -static void AIO_IOPool_setFile(IOPoolCtx_t *ctx, FILE* file) { +static void AIO_IOPool_setFile(IOPoolCtx_t* ctx, FILE* file) { assert(ctx!=NULL); AIO_IOPool_join(ctx); assert(ctx->availableJobsCount == ctx->totalIoJobs); ctx->file = file; } -static FILE* AIO_IOPool_getFile(IOPoolCtx_t *ctx) { +static FILE* AIO_IOPool_getFile(const IOPoolCtx_t* ctx) { return ctx->file; } /* AIO_IOPool_enqueueJob: * Enqueues an io job for execution. * The queued job shouldn't be used directly after queueing it. */ -static void AIO_IOPool_enqueueJob(IOJob_t *job) { - IOPoolCtx_t* ctx = (IOPoolCtx_t *)job->ctx; +static void AIO_IOPool_enqueueJob(IOJob_t* job) { + IOPoolCtx_t* const ctx = (IOPoolCtx_t *)job->ctx; if(ctx->threadPool) POOL_add(ctx->threadPool, ctx->poolFunction, job); else @@ -273,7 +271,7 @@ static void AIO_IOPool_enqueueJob(IOJob_t *job) { /* AIO_WritePool_acquireJob: * Returns an available write job to be used for a future write. */ -IOJob_t* AIO_WritePool_acquireJob(WritePoolCtx_t *ctx) { +IOJob_t* AIO_WritePool_acquireJob(WritePoolCtx_t* ctx) { return AIO_IOPool_acquireJob(&ctx->base); } @@ -290,7 +288,7 @@ void AIO_WritePool_enqueueAndReacquireWriteJob(IOJob_t **job) { /* AIO_WritePool_sparseWriteEnd: * Ends sparse writes to the current file. * Blocks on completion of all current write jobs before executing. */ -void AIO_WritePool_sparseWriteEnd(WritePoolCtx_t *ctx) { +void AIO_WritePool_sparseWriteEnd(WritePoolCtx_t* ctx) { assert(ctx != NULL); if(ctx->base.threadPool) POOL_joinJobs(ctx->base.threadPool); @@ -302,28 +300,28 @@ void AIO_WritePool_sparseWriteEnd(WritePoolCtx_t *ctx) { * Sets the destination file for future writes in the pool. * Requires completion of all queues write jobs and release of all otherwise acquired jobs. * Also requires ending of sparse write if a previous file was used in sparse mode. */ -void AIO_WritePool_setFile(WritePoolCtx_t *ctx, FILE* file) { +void AIO_WritePool_setFile(WritePoolCtx_t* ctx, FILE* file) { AIO_IOPool_setFile(&ctx->base, file); assert(ctx->storedSkips == 0); } /* AIO_WritePool_getFile: * Returns the file the writePool is currently set to write to. */ -FILE* AIO_WritePool_getFile(WritePoolCtx_t *ctx) { +FILE* AIO_WritePool_getFile(const WritePoolCtx_t* ctx) { return AIO_IOPool_getFile(&ctx->base); } /* AIO_WritePool_releaseIoJob: * Releases an acquired job back to the pool. Doesn't execute the job. */ -void AIO_WritePool_releaseIoJob(IOJob_t *job) { +void AIO_WritePool_releaseIoJob(IOJob_t* job) { AIO_IOPool_releaseIoJob(job); } /* AIO_WritePool_closeFile: * Ends sparse write and closes the writePool's current file and sets the file to NULL. * Requires completion of all queues write jobs and release of all otherwise acquired jobs. */ -int AIO_WritePool_closeFile(WritePoolCtx_t *ctx) { - FILE *dstFile = ctx->base.file; +int AIO_WritePool_closeFile(WritePoolCtx_t* ctx) { + FILE* const dstFile = ctx->base.file; assert(dstFile!=NULL || ctx->base.prefs->testMode!=0); AIO_WritePool_sparseWriteEnd(ctx); AIO_IOPool_setFile(&ctx->base, NULL); @@ -333,16 +331,16 @@ int AIO_WritePool_closeFile(WritePoolCtx_t *ctx) { /* AIO_WritePool_executeWriteJob: * Executes a write job synchronously. Can be used as a function for a thread pool. */ static void AIO_WritePool_executeWriteJob(void* opaque){ - IOJob_t* job = (IOJob_t*) opaque; - WritePoolCtx_t* ctx = (WritePoolCtx_t*) job->ctx; + IOJob_t* const job = (IOJob_t*) opaque; + WritePoolCtx_t* const ctx = (WritePoolCtx_t*) job->ctx; ctx->storedSkips = AIO_fwriteSparse(job->file, job->buffer, job->usedBufferSize, ctx->base.prefs, ctx->storedSkips); AIO_IOPool_releaseIoJob(job); } /* AIO_WritePool_create: * Allocates and sets and a new write pool including its included jobs. */ -WritePoolCtx_t* AIO_WritePool_create(FIO_prefs_t* const prefs, size_t bufferSize) { - WritePoolCtx_t* ctx = (WritePoolCtx_t*) malloc(sizeof(WritePoolCtx_t)); +WritePoolCtx_t* AIO_WritePool_create(const FIO_prefs_t* prefs, size_t bufferSize) { + WritePoolCtx_t* const ctx = (WritePoolCtx_t*) malloc(sizeof(WritePoolCtx_t)); if(!ctx) EXM_THROW(100, "Allocation error : not enough memory"); AIO_IOPool_init(&ctx->base, prefs, AIO_WritePool_executeWriteJob, bufferSize); ctx->storedSkips = 0; @@ -373,8 +371,8 @@ static void AIO_ReadPool_releaseAllCompletedJobs(ReadPoolCtx_t* ctx) { ctx->completedJobsCount = 0; } -static void AIO_ReadPool_addJobToCompleted(IOJob_t *job) { - ReadPoolCtx_t *ctx = (ReadPoolCtx_t *)job->ctx; +static void AIO_ReadPool_addJobToCompleted(IOJob_t* job) { + ReadPoolCtx_t* const ctx = (ReadPoolCtx_t *)job->ctx; if(ctx->base.threadPool) ZSTD_pthread_mutex_lock(&ctx->base.ioJobsMutex); assert(ctx->completedJobsCount < MAX_IO_JOBS); @@ -389,7 +387,7 @@ static void AIO_ReadPool_addJobToCompleted(IOJob_t *job) { * Looks through the completed jobs for a job matching the waitingOnOffset and returns it, * if job wasn't found returns NULL. * IMPORTANT: assumes ioJobsMutex is locked. */ -static IOJob_t* AIO_ReadPool_findNextWaitingOffsetCompletedJob_locked(ReadPoolCtx_t *ctx) { +static IOJob_t* AIO_ReadPool_findNextWaitingOffsetCompletedJob_locked(ReadPoolCtx_t* ctx) { IOJob_t *job = NULL; int i; /* This implementation goes through all completed jobs and looks for the one matching the next offset. @@ -408,7 +406,7 @@ static IOJob_t* AIO_ReadPool_findNextWaitingOffsetCompletedJob_locked(ReadPoolCt /* AIO_ReadPool_numReadsInFlight: * Returns the number of IO read jobs currrently in flight. */ -static size_t AIO_ReadPool_numReadsInFlight(ReadPoolCtx_t *ctx) { +static size_t AIO_ReadPool_numReadsInFlight(ReadPoolCtx_t* ctx) { const size_t jobsHeld = (ctx->currentJobHeld==NULL ? 0 : 1); return ctx->base.totalIoJobs - (ctx->base.availableJobsCount + ctx->completedJobsCount + jobsHeld); } @@ -416,7 +414,7 @@ static size_t AIO_ReadPool_numReadsInFlight(ReadPoolCtx_t *ctx) { /* AIO_ReadPool_getNextCompletedJob: * Returns a completed IOJob_t for the next read in line based on waitingOnOffset and advances waitingOnOffset. * Would block. */ -static IOJob_t* AIO_ReadPool_getNextCompletedJob(ReadPoolCtx_t *ctx) { +static IOJob_t* AIO_ReadPool_getNextCompletedJob(ReadPoolCtx_t* ctx) { IOJob_t *job = NULL; if (ctx->base.threadPool) ZSTD_pthread_mutex_lock(&ctx->base.ioJobsMutex); @@ -444,8 +442,8 @@ static IOJob_t* AIO_ReadPool_getNextCompletedJob(ReadPoolCtx_t *ctx) { /* AIO_ReadPool_executeReadJob: * Executes a read job synchronously. Can be used as a function for a thread pool. */ static void AIO_ReadPool_executeReadJob(void* opaque){ - IOJob_t* job = (IOJob_t*) opaque; - ReadPoolCtx_t* ctx = (ReadPoolCtx_t *)job->ctx; + IOJob_t* const job = (IOJob_t*) opaque; + ReadPoolCtx_t* const ctx = (ReadPoolCtx_t *)job->ctx; if(ctx->reachedEof) { job->usedBufferSize = 0; AIO_ReadPool_addJobToCompleted(job); @@ -464,14 +462,14 @@ static void AIO_ReadPool_executeReadJob(void* opaque){ AIO_ReadPool_addJobToCompleted(job); } -static void AIO_ReadPool_enqueueRead(ReadPoolCtx_t *ctx) { - IOJob_t *job = AIO_IOPool_acquireJob(&ctx->base); +static void AIO_ReadPool_enqueueRead(ReadPoolCtx_t* ctx) { + IOJob_t* const job = AIO_IOPool_acquireJob(&ctx->base); job->offset = ctx->nextReadOffset; ctx->nextReadOffset += job->bufferSize; AIO_IOPool_enqueueJob(job); } -static void AIO_ReadPool_startReading(ReadPoolCtx_t *ctx) { +static void AIO_ReadPool_startReading(ReadPoolCtx_t* ctx) { int i; for (i = 0; i < ctx->base.availableJobsCount; i++) { AIO_ReadPool_enqueueRead(ctx); @@ -481,7 +479,7 @@ static void AIO_ReadPool_startReading(ReadPoolCtx_t *ctx) { /* AIO_ReadPool_setFile: * Sets the source file for future read in the pool. Initiates reading immediately if file is not NULL. * Waits for all current enqueued tasks to complete if a previous file was set. */ -void AIO_ReadPool_setFile(ReadPoolCtx_t *ctx, FILE* file) { +void AIO_ReadPool_setFile(ReadPoolCtx_t* ctx, FILE* file) { assert(ctx!=NULL); AIO_IOPool_join(&ctx->base); AIO_ReadPool_releaseAllCompletedJobs(ctx); @@ -503,8 +501,8 @@ void AIO_ReadPool_setFile(ReadPoolCtx_t *ctx, FILE* file) { * Allocates and sets and a new readPool including its included jobs. * bufferSize should be set to the maximal buffer we want to read at a time, will also be used * as our basic read size. */ -ReadPoolCtx_t* AIO_ReadPool_create(FIO_prefs_t* const prefs, size_t bufferSize) { - ReadPoolCtx_t* ctx = (ReadPoolCtx_t*) malloc(sizeof(ReadPoolCtx_t)); +ReadPoolCtx_t* AIO_ReadPool_create(const FIO_prefs_t* prefs, size_t bufferSize) { + ReadPoolCtx_t* const ctx = (ReadPoolCtx_t*) malloc(sizeof(ReadPoolCtx_t)); if(!ctx) EXM_THROW(100, "Allocation error : not enough memory"); AIO_IOPool_init(&ctx->base, prefs, AIO_ReadPool_executeReadJob, bufferSize); @@ -535,7 +533,7 @@ void AIO_ReadPool_free(ReadPoolCtx_t* ctx) { /* AIO_ReadPool_consumeBytes: * Consumes byes from srcBuffer's beginning and updates srcBufferLoaded accordingly. */ -void AIO_ReadPool_consumeBytes(ReadPoolCtx_t *ctx, size_t n) { +void AIO_ReadPool_consumeBytes(ReadPoolCtx_t* ctx, size_t n) { assert(n <= ctx->srcBufferLoaded); ctx->srcBufferLoaded -= n; ctx->srcBuffer += n; @@ -543,7 +541,7 @@ void AIO_ReadPool_consumeBytes(ReadPoolCtx_t *ctx, size_t n) { /* AIO_ReadPool_releaseCurrentlyHeldAndGetNext: * Release the current held job and get the next one, returns NULL if no next job available. */ -static IOJob_t* AIO_ReadPool_releaseCurrentHeldAndGetNext(ReadPoolCtx_t *ctx) { +static IOJob_t* AIO_ReadPool_releaseCurrentHeldAndGetNext(ReadPoolCtx_t* ctx) { if (ctx->currentJobHeld) { AIO_IOPool_releaseIoJob((IOJob_t *)ctx->currentJobHeld); ctx->currentJobHeld = NULL; @@ -558,7 +556,7 @@ static IOJob_t* AIO_ReadPool_releaseCurrentHeldAndGetNext(ReadPoolCtx_t *ctx) { * Returns if srcBuffer has at least n bytes loaded or if we've reached the end of the file. * Return value is the number of bytes added to the buffer. * Note that srcBuffer might have up to 2 times jobBufferSize bytes. */ -size_t AIO_ReadPool_fillBuffer(ReadPoolCtx_t *ctx, size_t n) { +size_t AIO_ReadPool_fillBuffer(ReadPoolCtx_t* ctx, size_t n) { IOJob_t *job; int useCoalesce = 0; assert(n <= ctx->base.jobBufferSize); @@ -589,21 +587,21 @@ size_t AIO_ReadPool_fillBuffer(ReadPoolCtx_t *ctx, size_t n) { /* AIO_ReadPool_consumeAndRefill: * Consumes the current buffer and refills it with bufferSize bytes. */ -size_t AIO_ReadPool_consumeAndRefill(ReadPoolCtx_t *ctx) { +size_t AIO_ReadPool_consumeAndRefill(ReadPoolCtx_t* ctx) { AIO_ReadPool_consumeBytes(ctx, ctx->srcBufferLoaded); return AIO_ReadPool_fillBuffer(ctx, ctx->base.jobBufferSize); } /* AIO_ReadPool_getFile: * Returns the current file set for the read pool. */ -FILE* AIO_ReadPool_getFile(ReadPoolCtx_t *ctx) { +FILE* AIO_ReadPool_getFile(const ReadPoolCtx_t* ctx) { return AIO_IOPool_getFile(&ctx->base); } /* AIO_ReadPool_closeFile: * Closes the current set file. Waits for all current enqueued tasks to complete and resets state. */ -int AIO_ReadPool_closeFile(ReadPoolCtx_t *ctx) { - FILE* file = AIO_ReadPool_getFile(ctx); +int AIO_ReadPool_closeFile(ReadPoolCtx_t* ctx) { + FILE* const file = AIO_ReadPool_getFile(ctx); AIO_ReadPool_setFile(ctx, NULL); return fclose(file); } diff --git a/programs/fileio_asyncio.h b/programs/fileio_asyncio.h index 1b034c37fd8..cead10436f3 100644 --- a/programs/fileio_asyncio.h +++ b/programs/fileio_asyncio.h @@ -28,7 +28,7 @@ typedef struct { /* These struct fields should be set only on creation and not changed afterwards */ POOL_ctx* threadPool; int totalIoJobs; - FIO_prefs_t* prefs; + const FIO_prefs_t* prefs; POOL_function poolFunction; /* Controls the file we currently write to, make changes only by using provided utility functions */ @@ -116,7 +116,7 @@ void AIO_WritePool_setFile(WritePoolCtx_t *ctx, FILE* file); /* AIO_WritePool_getFile: * Returns the file the writePool is currently set to write to. */ -FILE* AIO_WritePool_getFile(WritePoolCtx_t *ctx); +FILE* AIO_WritePool_getFile(const WritePoolCtx_t* ctx); /* AIO_WritePool_closeFile: * Ends sparse write and closes the writePool's current file and sets the file to NULL. @@ -126,7 +126,7 @@ int AIO_WritePool_closeFile(WritePoolCtx_t *ctx); /* AIO_WritePool_create: * Allocates and sets and a new write pool including its included jobs. * bufferSize should be set to the maximal buffer we want to write to at a time. */ -WritePoolCtx_t* AIO_WritePool_create(FIO_prefs_t* const prefs, size_t bufferSize); +WritePoolCtx_t* AIO_WritePool_create(const FIO_prefs_t* prefs, size_t bufferSize); /* AIO_WritePool_free: * Frees and releases a writePool and its resources. Closes destination file. */ @@ -136,7 +136,7 @@ void AIO_WritePool_free(WritePoolCtx_t* ctx); * Allocates and sets and a new readPool including its included jobs. * bufferSize should be set to the maximal buffer we want to read at a time, will also be used * as our basic read size. */ -ReadPoolCtx_t* AIO_ReadPool_create(FIO_prefs_t* const prefs, size_t bufferSize); +ReadPoolCtx_t* AIO_ReadPool_create(const FIO_prefs_t* prefs, size_t bufferSize); /* AIO_ReadPool_free: * Frees and releases a readPool and its resources. Closes source file. */ @@ -164,7 +164,7 @@ void AIO_ReadPool_setFile(ReadPoolCtx_t *ctx, FILE* file); /* AIO_ReadPool_getFile: * Returns the current file set for the read pool. */ -FILE* AIO_ReadPool_getFile(ReadPoolCtx_t *ctx); +FILE* AIO_ReadPool_getFile(const ReadPoolCtx_t *ctx); /* AIO_ReadPool_closeFile: * Closes the current set file. Waits for all current enqueued tasks to complete and resets state. */ diff --git a/tests/playTests.sh b/tests/playTests.sh index 308a5780e05..648da6ecfbd 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -186,7 +186,7 @@ fi println "\n===> simple tests " -datagen -g500K > tmp +datagen > tmp zstd -h zstd -H zstd -V @@ -259,10 +259,12 @@ zstd -dc - < tmp.zst > $INTOVOID zstd -d < tmp.zst > $INTOVOID # implicit stdout when stdin is used zstd -d - < tmp.zst > $INTOVOID println "test : impose memory limitation (must fail)" -zstd -d -f tmp.zst -M2K -c > $INTOVOID && die "decompression needs more memory than allowed" -zstd -d -f tmp.zst --memlimit=2K -c > $INTOVOID && die "decompression needs more memory than allowed" # long command -zstd -d -f tmp.zst --memory=2K -c > $INTOVOID && die "decompression needs more memory than allowed" # long command -zstd -d -f tmp.zst --memlimit-decompress=2K -c > $INTOVOID && die "decompression needs more memory than allowed" # long command +datagen -g500K > tmplimit +zstd -f tmplimit +zstd -d -f tmplimit.zst -M2K -c > $INTOVOID && die "decompression needs more memory than allowed" +zstd -d -f tmplimit.zst --memlimit=2K -c > $INTOVOID && die "decompression needs more memory than allowed" # long command +zstd -d -f tmplimit.zst --memory=2K -c > $INTOVOID && die "decompression needs more memory than allowed" # long command +zstd -d -f tmplimit.zst --memlimit-decompress=2K -c > $INTOVOID && die "decompression needs more memory than allowed" # long command println "test : overwrite protection" zstd -q tmp && die "overwrite check failed!" println "test : force overwrite" From 53d68e0d51109b7f2c043a39a4bd5ae2f6aa73fe Mon Sep 17 00:00:00 2001 From: Yonatan Komornik Date: Wed, 26 Jan 2022 13:16:22 -0800 Subject: [PATCH 15/23] Asyncio Compression: Changed asyncio to be default behaviour and adjusted cli help --- programs/README.md | 1 + programs/fileio.c | 2 +- programs/fileio_asyncio.c | 10 ++++++++++ programs/fileio_asyncio.h | 4 ++++ programs/zstdcli.c | 7 +++---- 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/programs/README.md b/programs/README.md index 5570f90c3b4..b88cf78d71a 100644 --- a/programs/README.md +++ b/programs/README.md @@ -164,6 +164,7 @@ Advanced arguments : --filelist FILE : read list of files to operate upon from FILE --output-dir-flat DIR : processed files are stored into DIR --output-dir-mirror DIR : processed files are stored into DIR respecting original directory structure +--[no-]asyncio : use asynchronous IO (default: enabled) --[no-]check : during compression, add XXH64 integrity checksum to frame (default: enabled). If specified with -d, decompressor will ignore/validate checksums in compressed frame (default: validate). -- : All arguments after "--" are treated as files diff --git a/programs/fileio.c b/programs/fileio.c index a25eb2af730..c19a717eeaf 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -255,7 +255,7 @@ FIO_prefs_t* FIO_createPreferences(void) ret->literalCompressionMode = ZSTD_ps_auto; ret->excludeCompressedFiles = 0; ret->allowBlockDevices = 0; - ret->asyncIO = 0; + ret->asyncIO = AIO_supported(); return ret; } diff --git a/programs/fileio_asyncio.c b/programs/fileio_asyncio.c index 2d8b8a138b2..f988d338a79 100644 --- a/programs/fileio_asyncio.c +++ b/programs/fileio_asyncio.c @@ -129,6 +129,16 @@ AIO_fwriteSparseEnd(const FIO_prefs_t* const prefs, FILE* file, unsigned storedS * AsyncIO functionality ************************************************************************/ +/* AIO_supported: + * Returns 1 if AsyncIO is supported on the system, 0 otherwise. */ +int AIO_supported(void) { +#ifdef ZSTD_MULTITHREAD + return 1; +#else + return 0; +#endif +} + /* *********************************** * General IoPool implementation *************************************/ diff --git a/programs/fileio_asyncio.h b/programs/fileio_asyncio.h index cead10436f3..d07c46740c4 100644 --- a/programs/fileio_asyncio.h +++ b/programs/fileio_asyncio.h @@ -87,6 +87,10 @@ typedef struct { U64 offset; } IOJob_t; +/* AIO_supported: + * Returns 1 if AsyncIO is supported on the system, 0 otherwise. */ +int AIO_supported(void); + /* AIO_WritePool_releaseIoJob: * Releases an acquired job back to the pool. Doesn't execute the job. */ diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 53f0eca68e3..4355e047281 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -46,6 +46,7 @@ # include "zstdcli_trace.h" #endif #include "../lib/zstd.h" /* ZSTD_VERSION_STRING, ZSTD_minCLevel, ZSTD_maxCLevel */ +#include "fileio_asyncio.h" /*-************************************ @@ -179,7 +180,8 @@ static void usage_advanced(const char* programName) #ifdef UTIL_HAS_MIRRORFILELIST DISPLAYOUT( "--output-dir-mirror DIR : processed files are stored into DIR respecting original directory structure \n"); #endif - + if (AIO_supported()) + DISPLAYOUT( "--[no-]asyncio : use asynchronous IO (default: enabled) \n"); #ifndef ZSTD_NOCOMPRESS DISPLAYOUT( "--[no-]check : during compression, add XXH64 integrity checksum to frame (default: enabled)"); @@ -242,9 +244,6 @@ static void usage_advanced(const char* programName) DISPLAYOUT( " -l : print information about zstd compressed files \n"); DISPLAYOUT( "--test : test compressed file integrity \n"); DISPLAYOUT( " -M# : Set a memory usage limit for decompression \n"); -#ifdef ZSTD_MULTITHREAD - DISPLAYOUT( "--[no-]asyncio : use threaded asynchronous IO for output (default: disabled) \n"); -#endif # if ZSTD_SPARSE_DEFAULT DISPLAYOUT( "--[no-]sparse : sparse mode (default: enabled on file, disabled on stdout) \n"); # else From 00ecfcb4e129250a4cbcf4244f734d4a91955f32 Mon Sep 17 00:00:00 2001 From: Yonatan Komornik Date: Wed, 26 Jan 2022 15:33:40 -0800 Subject: [PATCH 16/23] fix output line --- programs/fileio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/fileio.c b/programs/fileio.c index c19a717eeaf..d7d7ad8e794 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -1322,7 +1322,7 @@ FIO_compressZstdFrame(FIO_ctx_t* const fCtx, /* display progress notifications */ if (g_display_prefs.displayLevel >= 3) { - DISPLAYUPDATE(3, "\r(L%i) Buffered :%6.*f%4s - Consumed :%6.*f%4s - Compressed :%6.*f%4s => %.2f%% ", + DISPLAYUPDATE(3, "\r(L%i) Buffered:%5.*f%s - Consumed:%5.*f%s - Compressed:%5.*f%s => %.2f%% ", compressionLevel, buffered_hrs.precision, buffered_hrs.value, buffered_hrs.suffix, consumed_hrs.precision, consumed_hrs.value, consumed_hrs.suffix, From 99a0b5d10ba36a0c31c7415473c2fbdc569a2876 Mon Sep 17 00:00:00 2001 From: Yonatan Komornik Date: Wed, 26 Jan 2022 17:30:56 -0800 Subject: [PATCH 17/23] Asyncio compression: fix a bug in lz4 usage --- programs/fileio.c | 7 ++++--- programs/fileio_asyncio.c | 16 ++++++++++------ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index d7d7ad8e794..49f75cac5c2 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -1179,8 +1179,9 @@ FIO_compressLz4Frame(cRess_t* ress, /* Main Loop */ while (ress->readCtx->srcBufferLoaded) { + size_t inSize = MIN(blockSize, ress->readCtx->srcBufferLoaded); size_t const outSize = LZ4F_compressUpdate(ctx, writeJob->buffer, writeJob->bufferSize, - ress->readCtx->srcBuffer, ress->readCtx->srcBufferLoaded, NULL); + ress->readCtx->srcBuffer, inSize, NULL); if (LZ4F_isError(outSize)) EXM_THROW(35, "zstd: %s: lz4 compression failed : %s", srcFileName, LZ4F_getErrorName(outSize)); @@ -1200,8 +1201,8 @@ FIO_compressLz4Frame(cRess_t* ress, AIO_WritePool_enqueueAndReacquireWriteJob(&writeJob); /* Read next block */ - AIO_ReadPool_consumeBytes(ress->readCtx, ress->readCtx->srcBufferLoaded); - readSize = AIO_ReadPool_fillBuffer(ress->readCtx, blockSize); + AIO_ReadPool_consumeBytes(ress->readCtx, inSize); + readSize = AIO_ReadPool_fillBuffer(ress->readCtx, blockSize); inFileSize += readSize; } diff --git a/programs/fileio_asyncio.c b/programs/fileio_asyncio.c index f988d338a79..08c0990f517 100644 --- a/programs/fileio_asyncio.c +++ b/programs/fileio_asyncio.c @@ -165,13 +165,13 @@ static void AIO_IOPool_createThreadPool(IOPoolCtx_t* ctx, const FIO_prefs_t* pre ctx->threadPool = NULL; if(prefs->asyncIO) { if (ZSTD_pthread_mutex_init(&ctx->ioJobsMutex, NULL)) - EXM_THROW(102,"Failed creating write availableJobs mutex"); + EXM_THROW(102,"Failed creating write availableJobs mutex"); /* We want MAX_IO_JOBS-2 queue items because we need to always have 1 free buffer to * decompress into and 1 buffer that's actively written to disk and owned by the writing thread. */ assert(MAX_IO_JOBS >= 2); ctx->threadPool = POOL_create(1, MAX_IO_JOBS - 2); if (!ctx->threadPool) - EXM_THROW(104, "Failed creating writer thread pool"); + EXM_THROW(104, "Failed creating writer thread pool"); } } @@ -587,11 +587,15 @@ size_t AIO_ReadPool_fillBuffer(ReadPoolCtx_t* ctx, size_t n) { job = AIO_ReadPool_releaseCurrentHeldAndGetNext(ctx); if(!job) return 0; - if(useCoalesce) + if(useCoalesce) { + assert(ctx->srcBufferLoaded + job->usedBufferSize <= 2*ctx->base.jobBufferSize); memcpy(ctx->coalesceBuffer + ctx->srcBufferLoaded, job->buffer, job->usedBufferSize); - else - ctx->srcBuffer = (U8*) job->buffer; - ctx->srcBufferLoaded += job->usedBufferSize; + ctx->srcBufferLoaded += job->usedBufferSize; + } + else { + ctx->srcBuffer = (U8 *) job->buffer; + ctx->srcBufferLoaded = job->usedBufferSize; + } return job->usedBufferSize; } From c989e4486819da7f110fdb378328b7db11fc722a Mon Sep 17 00:00:00 2001 From: Yonatan Komornik Date: Wed, 26 Jan 2022 23:14:09 -0800 Subject: [PATCH 18/23] CR fixes --- programs/fileio.c | 11 ++++------- programs/fileio_asyncio.c | 4 ++-- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index 49f75cac5c2..23dd1e9b0c5 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -995,7 +995,7 @@ FIO_compressGzFrame(const cRess_t* ress, /* buffers & handlers are used, but no } if (ret != Z_OK) - EXM_THROW(72, "zstd: %s: deflate error %d \n", srcFileName, ret); + EXM_THROW(72, "zstd: %s: deflate error %d \n", srcFileName, ret); { size_t const cSize = writeJob->bufferSize - strm.avail_out; if (cSize) { writeJob->usedBufferSize = cSize; @@ -1164,7 +1164,6 @@ FIO_compressLz4Frame(cRess_t* ress, assert(LZ4F_compressBound(blockSize, &prefs) <= writeJob->bufferSize); { - size_t readSize; size_t headerSize = LZ4F_compressBegin(ctx, writeJob->buffer, writeJob->bufferSize, &prefs); if (LZ4F_isError(headerSize)) EXM_THROW(33, "File header generation failed : %s", @@ -1174,8 +1173,7 @@ FIO_compressLz4Frame(cRess_t* ress, outFileSize += headerSize; /* Read first block */ - readSize = AIO_ReadPool_fillBuffer(ress->readCtx, blockSize); - inFileSize += readSize; + inFileSize += AIO_ReadPool_fillBuffer(ress->readCtx, blockSize); /* Main Loop */ while (ress->readCtx->srcBufferLoaded) { @@ -1202,8 +1200,7 @@ FIO_compressLz4Frame(cRess_t* ress, /* Read next block */ AIO_ReadPool_consumeBytes(ress->readCtx, inSize); - readSize = AIO_ReadPool_fillBuffer(ress->readCtx, blockSize); - inFileSize += readSize; + inFileSize += AIO_ReadPool_fillBuffer(ress->readCtx, blockSize); } /* End of Stream mark */ @@ -1945,13 +1942,13 @@ static int FIO_passThrough(dRess_t *ress) while(ress->readCtx->srcBufferLoaded) { size_t writeSize; - AIO_ReadPool_fillBuffer(ress->readCtx, blockSize); writeSize = MIN(blockSize, ress->readCtx->srcBufferLoaded); assert(writeSize <= writeJob->bufferSize); memcpy(writeJob->buffer, ress->readCtx->srcBuffer, writeSize); writeJob->usedBufferSize = writeSize; AIO_WritePool_enqueueAndReacquireWriteJob(&writeJob); AIO_ReadPool_consumeBytes(ress->readCtx, writeSize); + AIO_ReadPool_fillBuffer(ress->readCtx, blockSize); } assert(ress->readCtx->reachedEof); AIO_WritePool_releaseIoJob(writeJob); diff --git a/programs/fileio_asyncio.c b/programs/fileio_asyncio.c index 08c0990f517..b37c3d646b4 100644 --- a/programs/fileio_asyncio.c +++ b/programs/fileio_asyncio.c @@ -147,7 +147,7 @@ static IOJob_t *AIO_IOPool_createIoJob(IOPoolCtx_t *ctx, size_t bufferSize) { IOJob_t* const job = (IOJob_t*) malloc(sizeof(IOJob_t)); void* const buffer = malloc(bufferSize); if(!job || !buffer) - EXM_THROW(101, "Allocation error : not enough memory"); + EXM_THROW(101, "Allocation error : not enough memory"); job->buffer = buffer; job->bufferSize = bufferSize; job->usedBufferSize = 0; @@ -575,7 +575,7 @@ size_t AIO_ReadPool_fillBuffer(ReadPoolCtx_t* ctx, size_t n) { if (ctx->srcBufferLoaded >= n) return 0; - /* We still have bytes loaded, but enough to satisfy caller. We need to get the next job + /* We still have bytes loaded, but not enough to satisfy caller. We need to get the next job * and coalesce the remaining bytes with the next job's buffer */ if (ctx->srcBufferLoaded > 0) { useCoalesce = 1; From 70077442f906db436e64778eedd3663465486e2e Mon Sep 17 00:00:00 2001 From: Yonatan Komornik Date: Wed, 26 Jan 2022 23:50:10 -0800 Subject: [PATCH 19/23] Bug fix --- programs/fileio_asyncio.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/programs/fileio_asyncio.c b/programs/fileio_asyncio.c index b37c3d646b4..ad33110aa60 100644 --- a/programs/fileio_asyncio.c +++ b/programs/fileio_asyncio.c @@ -562,14 +562,15 @@ static IOJob_t* AIO_ReadPool_releaseCurrentHeldAndGetNext(ReadPoolCtx_t* ctx) { } /* AIO_ReadPool_fillBuffer: - * Makes sure buffer has at least n bytes loaded (n can't be bigger than jobBufferSize). - * Returns if srcBuffer has at least n bytes loaded or if we've reached the end of the file. + * Tries to fill the buffer with at least n or jobBufferSize bytes (whichever is smaller). + * Returns if srcBuffer has at least the expected number of bytes loaded or if we've reached the end of the file. * Return value is the number of bytes added to the buffer. * Note that srcBuffer might have up to 2 times jobBufferSize bytes. */ size_t AIO_ReadPool_fillBuffer(ReadPoolCtx_t* ctx, size_t n) { IOJob_t *job; int useCoalesce = 0; - assert(n <= ctx->base.jobBufferSize); + if(n > ctx->base.jobBufferSize) + n = ctx->base.jobBufferSize; /* We are good, don't read anything */ if (ctx->srcBufferLoaded >= n) From a74321f72ad4a16fd98c5987c0e60ab65a7c281a Mon Sep 17 00:00:00 2001 From: Yonatan Komornik Date: Fri, 28 Jan 2022 18:34:39 -0800 Subject: [PATCH 20/23] addFrame now uses a specific level so it won't crash with lz4 --- tests/playTests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/playTests.sh b/tests/playTests.sh index 648da6ecfbd..eb6d3271b32 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -1596,7 +1596,7 @@ println "\n===> zstd asyncio tests " addFrame() { datagen -g2M -s$2 >> tmp_uncompressed - datagen -g2M -s$2 | zstd --format=$1 >> tmp_compressed.zst + datagen -g2M -s$2 | zstd -1 --format=$1 >> tmp_compressed.zst } addTwoFrames() { From cd20f447136e88cb19506d8b2bf5d5eaa983b004 Mon Sep 17 00:00:00 2001 From: Yonatan Komornik Date: Mon, 31 Jan 2022 09:55:01 -0800 Subject: [PATCH 21/23] remove tmplimit when tests done --- tests/playTests.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/playTests.sh b/tests/playTests.sh index eb6d3271b32..64164d5bb6a 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -265,6 +265,7 @@ zstd -d -f tmplimit.zst -M2K -c > $INTOVOID && die "decompression needs more mem zstd -d -f tmplimit.zst --memlimit=2K -c > $INTOVOID && die "decompression needs more memory than allowed" # long command zstd -d -f tmplimit.zst --memory=2K -c > $INTOVOID && die "decompression needs more memory than allowed" # long command zstd -d -f tmplimit.zst --memlimit-decompress=2K -c > $INTOVOID && die "decompression needs more memory than allowed" # long command +rm -f tmplimit tmplimit.zst println "test : overwrite protection" zstd -q tmp && die "overwrite check failed!" println "test : force overwrite" From 5946fe57e049fd96c26f710ae0171450faef9ebd Mon Sep 17 00:00:00 2001 From: Yonatan Komornik Date: Mon, 31 Jan 2022 11:10:27 -0800 Subject: [PATCH 22/23] turn off autoflush for lz4 to mitigate level 12 bug --- programs/fileio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/programs/fileio.c b/programs/fileio.c index 23dd1e9b0c5..524c60292c0 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -1153,7 +1153,8 @@ FIO_compressLz4Frame(cRess_t* ress, assert(blockSize <= ress->readCtx->base.jobBufferSize); - prefs.autoFlush = 1; + /* autoflush off to mitigate a bug in lz4<=1.9.3 for compression level 12 */ + prefs.autoFlush = 0; prefs.compressionLevel = compressionLevel; prefs.frameInfo.blockMode = LZ4F_blockLinked; prefs.frameInfo.blockSizeID = LZ4F_max64KB; From 9336a2b88a62f207aed4838e5982fdce11bae25a Mon Sep 17 00:00:00 2001 From: Yonatan Komornik Date: Mon, 31 Jan 2022 14:29:26 -0800 Subject: [PATCH 23/23] Updated license for new files --- programs/fileio_asyncio.c | 2 +- programs/fileio_asyncio.h | 2 +- programs/fileio_common.h | 2 +- programs/fileio_types.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/programs/fileio_asyncio.c b/programs/fileio_asyncio.c index ad33110aa60..332292bbc1b 100644 --- a/programs/fileio_asyncio.c +++ b/programs/fileio_asyncio.c @@ -1,5 +1,5 @@ /* - * Copyright (c) Yann Collet, Facebook, Inc. + * Copyright (c) Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the diff --git a/programs/fileio_asyncio.h b/programs/fileio_asyncio.h index d07c46740c4..bf07f85947b 100644 --- a/programs/fileio_asyncio.h +++ b/programs/fileio_asyncio.h @@ -1,5 +1,5 @@ /* - * Copyright (c) Yann Collet, Facebook, Inc. + * Copyright (c) Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the diff --git a/programs/fileio_common.h b/programs/fileio_common.h index d33c19d7bd1..282c2f13b4d 100644 --- a/programs/fileio_common.h +++ b/programs/fileio_common.h @@ -1,5 +1,5 @@ /* - * Copyright (c) Yann Collet, Facebook, Inc. + * Copyright (c) Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the diff --git a/programs/fileio_types.h b/programs/fileio_types.h index 7366d77240c..cf566aa2063 100644 --- a/programs/fileio_types.h +++ b/programs/fileio_types.h @@ -1,5 +1,5 @@ /* - * Copyright (c) Yann Collet, Facebook, Inc. + * Copyright (c) Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the