Hello community,
here is the log from the commit of package pbzip2 for openSUSE:Factory
checked in at Mon Feb 21 00:54:05 CET 2011.
--------
--- pbzip2/pbzip2.changes 2010-12-20 19:51:46.000000000 +0100
+++ /mounts/work_src_done/STABLE/pbzip2/pbzip2.changes 2011-02-20 00:14:22.000000000 +0100
@@ -1,0 +2,15 @@
+Sat Feb 19 23:02:36 UTC 2011 - pascal.bleser@opensuse.org
+
+- update to 1.1.2:
+ * modifies Consumer_decompress throttling to prevent potential
+ deadlock/infinite loops in certain situations
+ * fixes a deadlock bug and performance issue when consumer is working with
+ long bzip2 sequences
+ * fixes a bug which caused a hang while decompressing a prematurely truncated
+ bzip2 stream
+ * fixes a hang on decompression of some truncated archives
+ * adds --ignore-trailing-garbage for non-standard archives such as gentoo
+ packages
+- reformatted changes file
+
+-------------------------------------------------------------------
@@ -4 +19,2 @@
-- reverting to upstream release, changed version to 1.1.0+0 to be newer than 1.1.0_git...
+- reverting to upstream release, changed version to 1.1.0+0 to be newer than
+ 1.1.0_git...
@@ -6,2 +22,4 @@
- * pbzip2-makefile.patch: adds support for BINDIR, MANDIR, DESTDIR and OPTFLAGS
- * pbzip2-fix_printf_format.patch: fix the many printf format errors in debug and error reporting statements
+ * pbzip2-makefile.patch: adds support for BINDIR, MANDIR, DESTDIR and
+ OPTFLAGS
+ * pbzip2-fix_printf_format.patch: fix the many printf format errors in debug
+ and error reporting statements
@@ -9,3 +27,6 @@
-- replace macros.pbzip2 with macros.pbzip2.in and a placeholder to inject the build time value of %{_bindir}
-- add symbolic links to the manpage for pbunzip2 and pbzcat too, thanks to darix for pointing this out
-- changed compression of upstream tarball from xz to bzip2 in order to build on older openSUSE and SLE releases
+- replace macros.pbzip2 with macros.pbzip2.in and a placeholder to inject the
+ build time value of %{_bindir}
+- add symbolic links to the manpage for pbunzip2 and pbzcat too, thanks to
+ darix for pointing this out
+- changed compression of upstream tarball from xz to bzip2 in order to build on
+ older openSUSE and SLE releases
@@ -28,3 +49,6 @@
- * improves the decompression performance of long bzip2 streams of large single-stream bzip2 blocks
- * pbzip2 should now decompress files created with bzip2 at least as quickly as bzip2, or slightly faster
- * handles decompression of long bzip2 streams incrementally instead of loading whole streams in memory at once
+ * improves the decompression performance of long bzip2 streams of large
+ single-stream bzip2 blocks
+ * pbzip2 should now decompress files created with bzip2 at least as quickly
+ as bzip2, or slightly faster
+ * handles decompression of long bzip2 streams incrementally instead of
+ loading whole streams in memory at once
@@ -36,3 +60,6 @@
- * adds support for multi-threaded decompression using STDIN/pipes and throttling compression to prevent memory exhaustion with slow output pipe
- * fixes a bug that did not allow command line parameters to be used when compressing data from STDIN
- * contains major improvements to protection of shared variables, error and signal handling, and program termination
+ * adds support for multi-threaded decompression using STDIN/pipes and
+ throttling compression to prevent memory exhaustion with slow output pipe
+ * fixes a bug that did not allow command line parameters to be used when
+ compressing data from STDIN
+ * contains major improvements to protection of shared variables, error and
+ signal handling, and program termination
calling whatdependson for head-i586
Old:
----
pbzip2-1.1.1.tar.bz2
New:
----
pbzip2-1.1.2.tar.bz2
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ pbzip2.spec ++++++
--- /var/tmp/diff_new_pack.QZ5hVR/_old 2011-02-21 00:53:50.000000000 +0100
+++ /var/tmp/diff_new_pack.QZ5hVR/_new 2011-02-21 00:53:50.000000000 +0100
@@ -1,7 +1,7 @@
#
-# spec file for package pbzip2 (Version 1.1.1+0)
+# spec file for package pbzip2
#
-# Copyright (c) 2010 SUSE LINUX Products GmbH, Nuernberg, Germany.
+# Copyright (c) 2011 SUSE LINUX Products GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -18,9 +18,9 @@
Name: pbzip2
-Version: 1.1.1+0
+Version: 1.1.2
Release: 1
-%define pkg_version 1.1.1
+%define pkg_version %{version}
License: BSD4c
Summary: Parallelized Implementation of bzip2
Url: http://compression.ca/pbzip2/
@@ -87,4 +87,5 @@
%doc %{_mandir}/man1/pbunzip2.1%{ext_man}
%doc %{_mandir}/man1/pbzcat.1%{ext_man}
%config %{_sysconfdir}/rpm/macros.%{name}
+
%changelog
++++++ pbzip2-1.1.1.tar.bz2 -> pbzip2-1.1.2.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pbzip2-1.1.1/AUTHORS new/pbzip2-1.1.2/AUTHORS
--- old/pbzip2-1.1.1/AUTHORS 2010-04-17 20:37:39.000000000 +0200
+++ new/pbzip2-1.1.2/AUTHORS 2011-02-19 11:10:22.000000000 +0100
@@ -181,8 +181,22 @@
disabled and enabled monitoring of segmented long bzip2 streams
- Fixed issue with Sun Studio compiler - required explicit declaration
of static const members in .cpp.
+ - consumer_decompress throttling loosed a bit to prevent potential
+ deadlock/infinite loop in certain situations. (Addition to all-empty-block
+ tails in OutputBuffer is non-blocking now).
+ - fixed error message for block size range (max size was wrong)
+ - consumer_decompress: fixed bug which caused hang while decompressing
+ prematurely truncated bzip2 stream.
+ - modified fileWriter to prevent from throttling when output buffers are full
+ (condition signalling added when block is ready to wake up sleeping writer early)
+ - Debug print bug fixed in queue::remove.
+ - Debuging and error handling improvements and refactoring.
+ - Fixed hang on decompress of some truncated archives (bug #590225).
+ - Implemented --ignore-trailing-garbage feature (bug #594868)
+ - Fixed hang on decompress of some truncated archives (bug #590225)
-Specials thanks for suggestions and testing
+
+Special thanks for suggestions and testing
-------------------------------------------
-Phillippe Welsh, James Terhune, Dru Lemley, Bryan Stillwell, George Chalissery, Kir Kolyshkin, Madhu Kangara, Mike Furr, Joergen Ramskov, Kurt Fitzner, Peter Cordes, Oliver Falk, Jindrich Novy, Benjamin Reed, Chris Dearman, Richard Russon, An�bal Monsalve Salazar, Jim Leonard, Paul Pluzhniko, Robert Archard, Coran Fisher, Ken Takusagawa, David Pyke, Matt Turner, Damien Ancelin, �lvaro Reguly, Ivan Voras, John Dalton, Sami Liedes, Rene Georgi, Ren� Rh�aume, Jeroen Roovers, Reinhard Schiedermeier, Kari Pahula, Elbert Pol, Nico Vrouwe, Eduardo Terol, Samuel Thibault, Michael Fuereder, Jari Aalto, Scott Emery, Steven Chamberlain, Yavor Nikolov, Nikita Zhuk, Joao Seabra, Conn Clark, Mark A. Haun, Tim Bielawa, Michal Gorny, Mikolaj Habdank, Christian Kujau, Marc-Christian Petersen, Piero Ottuzzi, Ephraim Ofir.
+Phillippe Welsh, James Terhune, Dru Lemley, Bryan Stillwell, George Chalissery, Kir Kolyshkin, Madhu Kangara, Mike Furr, Joergen Ramskov, Kurt Fitzner, Peter Cordes, Oliver Falk, Jindrich Novy, Benjamin Reed, Chris Dearman, Richard Russon, An�bal Monsalve Salazar, Jim Leonard, Paul Pluzhniko, Robert Archard, Coran Fisher, Ken Takusagawa, David Pyke, Matt Turner, Damien Ancelin, �lvaro Reguly, Ivan Voras, John Dalton, Sami Liedes, Rene Georgi, Ren� Rh�aume, Jeroen Roovers, Reinhard Schiedermeier, Kari Pahula, Elbert Pol, Nico Vrouwe, Eduardo Terol, Samuel Thibault, Michael Fuereder, Jari Aalto, Scott Emery, Steven Chamberlain, Yavor Nikolov, Nikita Zhuk, Joao Seabra, Conn Clark, Mark A. Haun, Tim Bielawa, Michal Gorny, Mikolaj Habdank, Christian Kujau, Marc-Christian Petersen, Piero Ottuzzi, Ephraim Ofir, Laszlo Ersek, Dima Tisnek.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pbzip2-1.1.1/COPYING new/pbzip2-1.1.2/COPYING
--- old/pbzip2-1.1.1/COPYING 2010-04-17 20:37:39.000000000 +0200
+++ new/pbzip2-1.1.2/COPYING 2011-02-19 11:10:22.000000000 +0100
@@ -1,4 +1,4 @@
-This program, "pbzip2" is copyright (C) 2003-2010 Jeff Gilchrist.
+This program, "pbzip2" is copyright (C) 2003-2011 Jeff Gilchrist.
All rights reserved.
The library "libbzip2" which pbzip2 uses, is copyright
@@ -37,4 +37,4 @@
Jeff Gilchrist, Ottawa, Canada.
pbzip2@compression.ca
-pbzip2 version 1.1.1 of April 17, 2010
+pbzip2 version 1.1.2 of Feb 19, 2011
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pbzip2-1.1.1/ChangeLog new/pbzip2-1.1.2/ChangeLog
--- old/pbzip2-1.1.1/ChangeLog 2010-04-17 20:37:39.000000000 +0200
+++ new/pbzip2-1.1.2/ChangeLog 2011-02-19 11:10:22.000000000 +0100
@@ -1,3 +1,27 @@
+Changes in 1.1.2 (Feb 19, 2011)
+- Fix directdecompress segfault when destination file can't be
+ opened (e.g. read-only) (bug #717852)
+- Implemented --ignore-trailing-garbage feature (bug #594868)
+- Fixed hang on decompress of some truncated archives (bug #590225)
+- Pulled an error check out of normal logic block for clarity
+- Debug print added after BZ2_bzDecompress to track it's return code.
+- A debug print fixed in queue::remove
+- Increased max memory usage limit from 1GB to 2GB
+- If no -m switch given on command line, default max memory limit
+ will now automatically increase from 100 MB to minimum amount
+ of memory required to support the number of CPUs requested
+- Improved performance when output buffer is full
+- Fixed bug which caused hang while decompressing prematurely
+ truncated bzip2 stream
+- Consumer_decompress throttling modified to prevent potential
+ deadlock/infinite loop in certain situations (Thanks to Laszlo
+ Ersek for finding and helping track down the cause of this bug)
+- Fixed deadlock bug and performance issue when consumer working
+ with long bzip2 sequences (Thanks to Tanguy Fautre for finding)
+- Fixed error message for block size range (max size was wrong)
+- Moved #include from pbzip2.cpp to pbzip2.h to fix
+ OS/2 compiler issue
+
Changes in 1.1.1 (Apr 17, 2010)
- Modified decompression to use low-level libbz2 API to improve
performance of long bzip2 streams of large single-stream bzip2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pbzip2-1.1.1/Makefile new/pbzip2-1.1.2/Makefile
--- old/pbzip2-1.1.1/Makefile 2010-04-17 20:37:39.000000000 +0200
+++ new/pbzip2-1.1.2/Makefile 2011-02-19 11:10:22.000000000 +0100
@@ -27,6 +27,12 @@
# Comment out CFLAGS line below to disable Thread stack size customization
CFLAGS += -DUSE_STACKSIZE_CUSTOMIZATION
+# Comment out CFLAGS line below to explicity set ignore trailing garbage
+# default behavior: 0 - disabled; 1 - enabled (ignore garbage by default)
+# If IGNORE_TRAILING_GARBAGE is not defined: behavior is automatically determined
+# by program name: bzip2, bunzip2, bzcat - ignore garbage; otherwise - not.
+#CFLAGS += -DIGNORE_TRAILING_GARBAGE=1
+
# On some compilers -pthreads
CFLAGS += -pthread
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pbzip2-1.1.1/README new/pbzip2-1.1.2/README
--- old/pbzip2-1.1.1/README 2010-04-17 20:37:39.000000000 +0200
+++ new/pbzip2-1.1.2/README 2011-02-19 11:10:22.000000000 +0100
@@ -1,6 +1,6 @@
-April 17, 2010
+Feb 19, 2011
-Parallel BZIP2 v1.1.1 - by: Jeff Gilchrist
+Parallel BZIP2 v1.1.2 - by: Jeff Gilchrist
Available at: http://compression.ca/
This is the README for pbzip2, a parallel implementation of the
@@ -135,6 +135,7 @@
-V Display version info for pbzip2 then exit
-z,--compress Compress file (default)
-1,--fast ... -9,--best Set BWT block size to 100k .. 900k (default 900k).
+ --ignore-trailing-garbage=# Ignore trailing garbage flag (1 - ignored; 0 - forbidden)
Example: pbzip2 myfile.tar
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pbzip2-1.1.1/pbzip2.1 new/pbzip2-1.1.2/pbzip2.1
--- old/pbzip2-1.1.1/pbzip2.1 2010-04-17 20:37:39.000000000 +0200
+++ new/pbzip2-1.1.2/pbzip2.1 2011-02-19 11:10:22.000000000 +0100
@@ -1,6 +1,6 @@
.TH pbzip2 1
.SH NAME
-pbzip2 \- parallel bzip2 file compressor, v1.1.1
+pbzip2 \- parallel bzip2 file compressor, v1.1.2
.SH SYNOPSIS
.B pbzip2
.RB [ " \-123456789 " ]
@@ -83,6 +83,9 @@
.TP
.B \-1,\-\-fast ... \-9,\-\-best
Set BWT block size to 100k .. 900k (default 900k).
+.TP
+.B \-\-ignore-trailing-garbage=#
+Ignore trailing garbage flag (1 - ignored; 0 - forbidden)
.SH FILE SIZES
You should be able to compress files larger than 4GB with
.I pbzip2.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pbzip2-1.1.1/pbzip2.cpp new/pbzip2-1.1.2/pbzip2.cpp
--- old/pbzip2-1.1.1/pbzip2.cpp 2010-04-17 20:37:39.000000000 +0200
+++ new/pbzip2-1.1.2/pbzip2.cpp 2011-02-19 11:10:22.000000000 +0100
@@ -9,7 +9,7 @@
* - uses libbzip2 by Julian Seward (http://sources.redhat.com/bzip2/)
* - Major contributions by Yavor Nikolov
*
- * Date : April 17, 2010
+ * Date : Feb 19, 2011
*
* TODO
* Known Issues
@@ -169,6 +169,25 @@
* disabled and enabled monitoring of segmented long bzip2 streams
* - Fixed issue with Sun Studio compiler - required explicit declaration
* of static const members in .cpp.
+ * - consumer_decompress throttling loosed a bit to prevent potential
+ * deadlock/infinite loop in certain situations. (Addition to all-empty-block
+ * tails in OutputBuffer is non-blocking now).
+ * - fixed error message for block size range (max size was wrong)
+ * - consumer_decompress: fixed bug which caused hang while decompressing
+ * prematurely truncated bzip2 stream.
+ * - modified fileWriter to prevent from throttling when output buffers are full
+ * (condition signalling added when block is ready to wake up sleeping writer early)
+ * - Fixed deadlock bug possible with stuck consumers waiting for other one
+ * on long multi-segment sequence.
+ * - Resolved performance issue: all have been waiting for any consumer
+ * working on long-sequence until it's finished even when there were enough
+ * free slots in the input queue.
+ * - Debug print bug fixed in queue::remove.
+ * - Debuging and error handling improvements and refactoring.
+ * - Fixed hang on decompress of some truncated archives (bug #590225).
+ * - Implemented --ignore-trailing-garbage feature (bug #594868)
+ * - Fixed hang on decompress of some truncated archives (bug #590225)
+ *
*
* Specials thanks for suggestions and testing: Phillippe Welsh,
* James Terhune, Dru Lemley, Bryan Stillwell, George Chalissery,
@@ -182,10 +201,10 @@
* Jari Aalto, Scott Emery, Steven Chamberlain, Yavor Nikolov, Nikita Zhuk,
* Joao Seabra, Conn Clark, Mark A. Haun, Tim Bielawa, Michal Gorny,
* Mikolaj Habdank, Christian Kujau, Marc-Christian Petersen, Piero Ottuzzi,
- * Ephraim Ofir.
+ * Ephraim Ofir, Laszlo Ersek, Dima Tisnek, Tanguy Fautre.
*
*
- * This program, "pbzip2" is copyright (C) 2003-2010 Jeff Gilchrist.
+ * This program, "pbzip2" is copyright (C) 2003-2011 Jeff Gilchrist.
* All rights reserved.
*
* The library "libbzip2" which pbzip2 uses, is copyright
@@ -224,7 +243,7 @@
*
* Jeff Gilchrist, Ottawa, Canada.
* pbzip2@compression.ca
- * pbzip2 version 1.1.1 of April 17, 2010
+ * pbzip2 version 1.1.2 of Feb 19, 2011
*
*/
#include "pbzip2.h"
@@ -240,7 +259,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -260,6 +278,7 @@
static int finishedFlag = 0; // Main thread work finished (about to exit)
static int unfinishedWorkCleaned = 0;
static int numCPU = 2;
+static int IgnoreTrailingGarbageFlag = 0; // ingnore trailing garbage on decompress flag
static int QUEUESIZE = 2;
static int SIG_HANDLER_QUIT_SIGNAL = SIGUSR1; // signal used to stop SignalHandlerThread
#ifdef USE_STACKSIZE_CUSTOMIZATION
@@ -278,6 +297,7 @@
static size_t NumBufferedTailBlocks = 0;
static size_t NumBufferedBlocksMax = 0;
static int NextBlockToWrite;
+static int LastGoodBlock; // set only to terminate write prematurely (ignoring garbage)
static size_t OutBufferPosToWrite; // = 0; // position in output buffer
static int Verbosity = 0;
static int QuietMode = 1;
@@ -294,6 +314,8 @@
static pthread_mutex_t ProgressIndicatorsMutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t *notTooMuchNumBuffered;
static pthread_cond_t TerminateCond = PTHREAD_COND_INITIALIZER;
+static pthread_cond_t OutBufferHeadNotEmpty = PTHREAD_COND_INITIALIZER;
+static pthread_cond_t ErrStateChangeCond = PTHREAD_COND_INITIALIZER;
static pthread_attr_t ChildThreadAttributes;
static struct stat fileMetaData;
static const char *sigInFilename = NULL;
@@ -308,6 +330,9 @@
inline int syncGetTerminateFlag();
inline void syncSetTerminateFlag(int newValue);
inline void syncSetFinishedFlag(int newValue);
+inline void setLastGoodBlock(int newValue);
+inline void syncSetLastGoodBlock(int newValue);
+inline int syncGetLastGoodBlock();
void cleanupUnfinishedWork();
void cleanupAndQuit(int exitCode);
int initSignalMask();
@@ -333,6 +358,7 @@
void outputBufferInit(size_t size);
outBuff * outputBufferAdd(const outBuff & element, const char *caller);
outBuff * outputBufferSeqAddNext(outBuff * preveElement, outBuff * newElement);
+inline size_t getOutputBufferPos(int blockNum);
int getFileMetaData(const char *);
int writeFileMetaData(const char *);
int testBZ2ErrorHandling(int, BZFILE *, int);
@@ -340,6 +366,21 @@
ssize_t bufread(int hf, char *buf, size_t bsize);
int detectCPUs(void);
+inline bool isIgnoredTrailingGarbage();
+int waitForPreviousBlock(int blockNum);
+inline int getLastGoodBlockBeforeErr(int errBlockNumber, int outSequenceNumber);
+inline int issueDecompressError(int bzret, const outBuff * fileData,
+ int outSequenceNumber, const bz_stream & strm, const char * errmsg,
+ int exitCode);
+int decompressErrCheckSingle(int bzret, const outBuff * fileData,
+ int outSequenceNumber, const bz_stream & strm, const char * errmsg,
+ bool isTrailingGarbageErr);
+int decompressErrCheck(int bzret, const outBuff * fileData,
+ int outSequenceNumber, const bz_stream & strm);
+int producerDecompressCheckInterrupt(int hInfile, outBuff *& fileData, int lastBlock);
+
+
+
/*
* Pointers to functions used by plain C pthreads API require C calling
* conventions.
@@ -599,6 +640,52 @@
safe_mutex_unlock(&TerminateFlagMutex);
}
+inline void setLastGoodBlock(int newValue)
+{
+ #ifdef PBZIP_DEBUG
+ unsigned long long thid = (unsigned long long) pthread_self();
+ fprintf(stderr, "(%"PRIu64") setLastGoodBlock: %d -> %d\n", thid, LastGoodBlock, newValue );
+ #endif
+
+ if ( (LastGoodBlock == -1) || (newValue < LastGoodBlock) )
+ {
+ LastGoodBlock = newValue;
+
+ safe_cond_signal(&ErrStateChangeCond);
+ safe_cond_signal(&OutBufferHeadNotEmpty);
+
+ // wake up all other possibly blocked on cond threads
+ pthread_cond_broadcast(notTooMuchNumBuffered);
+ if (FifoQueue != NULL)
+ {
+ pthread_cond_broadcast(FifoQueue->notFull);
+ pthread_cond_broadcast(FifoQueue->notEmpty);
+ }
+ }
+}
+
+inline void syncSetLastGoodBlock(int newValue)
+{
+ safe_mutex_lock(OutMutex);
+ setLastGoodBlock(newValue);
+ safe_mutex_unlock(OutMutex);
+}
+
+inline int syncGetLastGoodBlock()
+{
+ int ret;
+ safe_mutex_lock(OutMutex);
+ ret = LastGoodBlock;
+ safe_mutex_unlock(OutMutex);
+
+ return ret;
+}
+
+inline bool isIgnoredTrailingGarbage()
+{
+ return (IgnoreTrailingGarbageFlag != 0);
+}
+
/*
*********************************************************
Print error message and optionally exit or abort
@@ -630,6 +717,226 @@
return exitCode;
}
+/**
+ *
+ * @return -1 - terminate flag set (error)
+ * 0 - prev block is OK
+ * 2 - lower block number already in error state
+ */
+int waitForPreviousBlock(int blockNum)
+{
+ #ifdef PBZIP_DEBUG
+ unsigned long long thid = (unsigned long long) pthread_self();
+ fprintf(stderr, "(%"PRIu64") waitForPreviousBlock before check: LastGoodBlock=%d; blockNum=%d; NextBlockToWrite=%d\n",
+ thid,
+ LastGoodBlock, blockNum, NextBlockToWrite );
+ #endif
+
+ for (;;)
+ {
+ if (syncGetTerminateFlag() != 0)
+ {
+ #ifdef PBZIP_DEBUG
+ fprintf(stderr, "(%"PRIu64") waitForPreviousBlock terminated [%d]: blockNum=%d\n",
+ thid, -1, blockNum );
+ #endif
+ return -1;
+ }
+
+ safe_mutex_lock(OutMutex);
+
+ #ifdef PBZIP_DEBUG
+ fprintf(stderr, "(%"PRIu64") waitForPreviousBlock before check: LastGoodBlock=%d; blockNum=%d; NextBlockToWrite=%d\n",
+ thid, LastGoodBlock, blockNum, NextBlockToWrite );
+ #endif
+
+ if (blockNum <= NextBlockToWrite)
+ {
+ #ifdef PBZIP_DEBUG
+ fprintf(stderr, "(%"PRIu64") waitForPreviousBlock exit [%d]: LastGoodBlock=%d; blockNum=%d; NextBlockToWrite=%d\n",
+ thid, 0, LastGoodBlock, blockNum, NextBlockToWrite );
+ #endif
+ safe_mutex_unlock(OutMutex);
+ return 0;
+ }
+
+ if ( (LastGoodBlock != -1) && (LastGoodBlock < blockNum) )
+ {
+ #ifdef PBZIP_DEBUG
+ fprintf(stderr, "(%"PRIu64") waitForPreviousBlock exit [%d]: LastGoodBlock=%d; blockNum=%d; NextBlockToWrite=%d\n",
+ thid, 2, LastGoodBlock, blockNum, NextBlockToWrite );
+ #endif
+ safe_mutex_unlock(OutMutex);
+ return 2;
+ }
+
+ #ifdef PBZIP_DEBUG
+ fprintf(stderr, "(%"PRIu64") waitForPreviousBlock to sleep: LastGoodBlock=%d; blockNum=%d; NextBlockToWrite=%d\n",
+ thid, LastGoodBlock, blockNum, NextBlockToWrite );
+ #endif
+
+ safe_cond_timed_wait(&ErrStateChangeCond, OutMutex, 1, "waitForPreviousBlock");
+
+ safe_mutex_unlock(OutMutex);
+ }
+}
+
+/**
+ *
+ * @param errBlockNumber
+ * @param outSequenceNumber
+ * @return Last input block not after the given which resulted in good out blocks.
+ * -1 if such don't exist.
+ */
+inline int getLastGoodBlockBeforeErr(int errBlockNumber, int outSequenceNumber)
+{
+ // if we got the error just in the beginning of a bzip2 stream
+ if ( outSequenceNumber != -1 )
+ {
+ return errBlockNumber;
+ }
+ else
+ {
+ return errBlockNumber - 1;
+ }
+}
+
+/**
+ * Helper function delegating to handle_error with the relevant error
+ * message
+ *
+ * @param bzret
+ * @param fileData
+ * @param outSequenceNumber
+ * @param strm
+ * @param errmsg
+ * @param exitCode
+ * @return exitCode is returned
+ */
+inline int issueDecompressError(int bzret, const outBuff * fileData,
+ int outSequenceNumber, const bz_stream & strm, const char * errmsg,
+ int exitCode)
+{
+ handle_error(EF_EXIT, exitCode,
+ "pbzip2: %s: ret=%d; block=%d; seq=%d; isLastInSeq=%d; avail_in=%d\n",
+ errmsg, bzret, fileData->blockNumber,
+ outSequenceNumber, (int)fileData->isLastInSequence, strm.avail_in);
+ return exitCode;
+}
+
+/**
+ * Handle an error condition which is either trailing garbage-like one or not.
+ *
+ *
+ * @param bzret
+ * @param fileData
+ * @param outSequenceNumber
+ * @param strm
+ * @param errmsg
+ * @param isTrailingGarbageErr
+ * @return ret < 0 - fatal error;
+ * 0 - OK (no error at all);
+ * 1 - first block of ignored trailing garbage;
+ * 2 - error already signalled for earlier block
+ */
+int decompressErrCheckSingle(int bzret, const outBuff * fileData,
+ int outSequenceNumber, const bz_stream & strm, const char * errmsg,
+ bool isTrailingGarbageErr)
+{
+ int lastGoodBlock = getLastGoodBlockBeforeErr(fileData->blockNumber, outSequenceNumber);
+
+ #ifdef PBZIP_DEBUG
+ fprintf(stderr, "enter decompressErrCheckSingle: msg=%s; ret=%d; block=%d; seq=%d; isLastInSeq=%d; avail_in=%d; lastGoodBlock=%d\n",
+ errmsg, bzret, fileData->blockNumber,
+ outSequenceNumber, (int)fileData->isLastInSequence, strm.avail_in, lastGoodBlock);
+ #endif
+
+ if ( (lastGoodBlock == -1) || !isIgnoredTrailingGarbage() )
+ {
+ issueDecompressError(bzret, fileData, outSequenceNumber, strm, errmsg, -1);
+ return -1;
+ }
+ else
+ {
+ // Cut off larger block numbers
+ syncSetLastGoodBlock(lastGoodBlock);
+ // wait until the state of previous block is known
+ int prevState = waitForPreviousBlock(lastGoodBlock);
+
+ if (prevState == 0)
+ {
+ // we're the first error block
+
+ if (isTrailingGarbageErr)
+ {
+ // Trailing garbage detected and ignored - not a fatal warning
+ if (QuietMode != 1)
+ {
+ fprintf(stderr, "pbzip2: *WARNING: Trailing garbage after EOF ignored!\n");
+ }
+ return 1;
+ }
+ else
+ {
+ // the first error is not kind of trailing garbage -> fatal one
+ issueDecompressError(bzret, fileData, outSequenceNumber, strm, errmsg, -1);
+ return -1;
+ }
+ }
+ else if (prevState == 2)
+ {
+ // we're not the first error
+ return 2;
+ }
+ else // (prevState == -1)
+ {
+ // fatal state encountered
+ return -1;
+ }
+ }
+}
+
+/**
+ *
+ * @param bzret
+ * @param fileData
+ * @param outSequenceNumber
+ * @param strm
+ * @return ret < 0 - fatal error;
+ * 0 - OK (no error at all);
+ * 1 - first block of ignored trailing garbage;
+ * 2 - error already signalled for earlier block
+ */
+int decompressErrCheck(int bzret, const outBuff * fileData,
+ int outSequenceNumber, const bz_stream & strm)
+{
+ if ( (bzret == BZ_STREAM_END) &&
+ ((strm.avail_in != 0) || !fileData->isLastInSequence) )
+ {
+ // Potential trailing garbage
+ return decompressErrCheckSingle(bzret, fileData, outSequenceNumber, strm,
+ "*ERROR during BZ2_bzDecompress - trailing garbage", true);
+ }
+ else if ( (bzret != BZ_STREAM_END) && (bzret != BZ_OK) )
+ {
+ return decompressErrCheckSingle(bzret, fileData, outSequenceNumber, strm,
+ "*ERROR during BZ2_bzDecompress - failure exit code", false);
+ }
+ else if ( strm.avail_in != 0 )
+ {
+ return decompressErrCheckSingle(bzret, fileData, outSequenceNumber, strm,
+ "*ERROR unconsumed in after BZ2_bzDecompress loop", false);
+ }
+ else if ( (bzret != BZ_STREAM_END) && fileData->isLastInSequence )
+ {
+ return decompressErrCheckSingle(bzret, fileData, outSequenceNumber, strm,
+ "*ERROR on decompress - last in segment reached before BZ_STREAM_END",
+ false);
+ }
+
+ return 0;
+}
+
/*
* Initialize and set thread signal mask
*/
@@ -871,6 +1178,49 @@
return (s != searchBufEnd) ? s : NULL;
}
+/**
+ * Check for interrupt conditions - report if any and perform the relevant
+ * cleanup
+ *
+ * @param hInfile
+ * @param fileData
+ * @param lastBlock
+ * @return 0 - not interrupted; 1 - interrupted (terminate flag or other error encountered)
+ */
+int producerDecompressCheckInterrupt(int hInfile, outBuff *& fileData, int lastBlock)
+{
+ bool isInterrupted = false;
+
+ if (syncGetLastGoodBlock() != -1)
+ {
+ isInterrupted = true;
+
+ #ifdef PBZIP_DEBUG
+ fprintf (stderr, "producer_decompress: interrupt1 - LastGoodBlock set. "
+ "Last produced=%d\n", lastBlock);
+ #endif
+ }
+ if (syncGetTerminateFlag() != 0)
+ {
+ isInterrupted = true;
+
+ #ifdef PBZIP_DEBUG
+ fprintf (stderr, "producer_decompress: interrupt2 - TerminateFlag set. "
+ "Last produced=%d\n", lastBlock);
+ #endif
+ }
+
+ if (isInterrupted)
+ {
+ close(hInfile);
+ disposeMemorySingle(fileData);
+
+ return 1;
+ }
+
+ return 0;
+}
+
/*
*********************************************************
Function works in single pass. It's Splitting long
@@ -893,6 +1243,11 @@
fprintf(stderr, " -> Bytes Read: %u bytes...\n", fileData->bufSize);
#endif
+ if (producerDecompressCheckInterrupt(hInfile, fileData, NumBlocks) != 0)
+ {
+ return 0;
+ }
+
if (QuietMode != 1)
{
// give warning to user if block is larger than 250 million bytes
@@ -912,6 +1267,12 @@
fprintf (stderr, "producer: queue FULL.\n");
#endif
safe_cond_wait (fifo->notFull, fifo->mut);
+
+ if (producerDecompressCheckInterrupt(hInfile, fileData, NumBlocks) != 0)
+ {
+ safe_mutex_unlock(fifo->mut);
+ return 0;
+ }
}
#ifdef PBZIP_DEBUG
fprintf(stderr, "producer: Buffer: %x Size: %"PRIu64" Block: %d\n", fileData->buf,
@@ -936,7 +1297,8 @@
// last stream is always dummy one (either error or eof)
delete fileData;
- if (bz2StreamScanner.failed() || !bz2StreamScanner.eof())
+
+ if (bz2StreamScanner.failed())
{
handle_error(EF_EXIT, 1, "pbzip2: producer_decompress: *ERROR: when reading bzip2 input stream\n");
return -1;
@@ -957,6 +1319,45 @@
return 0;
}
+/**
+ * Check for interrupt conditions - report if any and perform the relevant
+ * cleanup
+ *
+ * @return 0 - not interrupted; 1 - interrupted (terminate flag or other error encountered)
+ */
+int consumerDecompressCheckInterrupt(const outBuff * lastElement)
+{
+ bool isInterrupted = false;
+
+ #ifdef PBZIP_DEBUG
+ unsigned long long thid = (unsigned long long) pthread_self();
+ #endif
+
+ if (syncGetTerminateFlag() != 0)
+ {
+ isInterrupted = true;
+
+ #ifdef PBZIP_DEBUG
+ fprintf (stderr, "(%"PRIu64") producer_decompress: interrupt1 - TerminateFlag set.\n", thid);
+ #endif
+ }
+ if ( (syncGetLastGoodBlock() != -1) &&
+ ( (lastElement == NULL) || (lastElement->blockNumber > syncGetLastGoodBlock()) ) )
+ {
+ isInterrupted = true;
+
+ #ifdef PBZIP_DEBUG
+ fprintf (stderr, "(%"PRIu64") consumer_decompress: terminating1 - LastGoodBlock set [%d].\n", thid, syncGetLastGoodBlock());
+ #endif
+ }
+
+ if (isInterrupted)
+ {
+ return 1;
+ }
+
+ return 0;
+}
/*
*********************************************************
@@ -970,8 +1371,9 @@
char *DecompressedData = NULL;
unsigned int outSize = 0;
outBuff * prevOutBlockInSequence = NULL;
- int outSequenceNumber = 0; // sequence number in multi-part output blocks
+ int outSequenceNumber = -1; // sequence number in multi-part output blocks
unsigned int processedIn = 0;
+ int errState = 0;
bz_stream strm;
strm.bzalloc = NULL;
@@ -980,17 +1382,14 @@
for (;;)
{
- if (syncGetTerminateFlag() != 0)
- {
- #ifdef PBZIP_DEBUG
- fprintf (stderr, "consumer: terminating1 - terminateFlag set\n");
- #endif
- return (NULL);
- }
-
safe_mutex_lock(fifo->mut);
for (;;)
{
+ if (consumerDecompressCheckInterrupt(fileData) != 0)
+ {
+ return (NULL);
+ }
+
if (!fifo->empty && (fifo->remove(fileData) == 1))
{
// block retreived - break the loop and continue further
@@ -1006,13 +1405,24 @@
// finished - either OK or terminated forcibly
pthread_mutex_unlock(fifo->mut);
// BZ2_bzDecompressEnd( &strm );
- if (lastFileData != NULL)
+
+ if ((syncGetTerminateFlag() == 0) && (outSequenceNumber != -1))
{
- delete lastFileData;
+ handle_error(EF_EXIT, -1, "pbzip2: *ERROR on decompress - "
+ "premature end of archive stream (block=%d; seq=%d; outseq=%d)!\n",
+ lastFileData->blockNumber,
+ lastFileData->sequenceNumber,
+ outSequenceNumber);
}
#ifdef PBZIP_DEBUG
- fprintf (stderr, "consumer: exiting2\n");
+ else
+ {
+ fprintf (stderr, "consumer: exiting2\n");
+ }
#endif
+
+ disposeMemorySingle( lastFileData );
+
return (NULL);
}
@@ -1024,6 +1434,7 @@
}
#ifdef PBZIP_DEBUG
+ fprintf(stderr, "consumer: FileData: %x\n", fileData);
fprintf(stderr, "consumer: Buffer: %x Size: %u Block: %d\n",
fileData->buf, (unsigned)fileData->bufSize, fileData->blockNumber);
#endif
@@ -1090,12 +1501,27 @@
bzret = BZ2_bzDecompress(&strm);
processedIn += (availIn - strm.avail_in);
+ #ifdef PBZIP_DEBUG
+ fprintf(stderr, "decompress: BZ2_bzDecompress=%d; block=%d; seq=%d; prev=%llx; avail_in=%u; avail_out=%u\n",
+ bzret,
+ fileData->blockNumber, outSequenceNumber,
+ (unsigned long long) prevOutBlockInSequence,
+ strm.avail_in, strm.avail_out);
+ #endif
+
// issue out block if out buffer is full or stream end is detected
if ( ((bzret == BZ_OK) && strm.avail_out == 0) || (bzret == BZ_STREAM_END) )
{
outBuff * addret = NULL;
unsigned int len = outSize - strm.avail_out;
bool isLast = (bzret == BZ_STREAM_END);
+
+ if ( isLast && ( (strm.avail_in != 0) || !fileData->isLastInSequence ) )
+ {
+ // trailng garbage detected
+ syncSetLastGoodBlock(fileData->blockNumber);
+ }
+
if (outSequenceNumber>0)
{
++outSequenceNumber;
@@ -1122,10 +1548,7 @@
}
else // sequenceNumber = 0
{
- if (bzret == BZ_OK)
- {
- ++outSequenceNumber;
- }
+ outSequenceNumber = (bzret == BZ_OK) ? 1 : 0;
addret = outputBufferAdd(outBuff(
DecompressedData, len,
fileData->blockNumber,
@@ -1150,40 +1573,25 @@
DecompressedData = NULL;
}
}
-
- if ((bzret != BZ_STREAM_END) && (bzret != BZ_OK))
- {
- handle_error(EF_EXIT, -1, "pbzip2: *ERROR during BZ2_bzDecompress: ret=%d; block=%d; seq=%d; avail_in=%d\n",
- bzret, fileData->blockNumber, outSequenceNumber, strm.avail_in);
- return (NULL);
- }
-
- if (strm.avail_in != 0)
- {
- handle_error(EF_EXIT, -1, "pbzip2: *ERROR unconsumed in after BZ2_bzDecompress loop:"
- "ret=%d; block=%d; seq=%d; avail_in=%d\n",
- bzret, fileData->blockNumber, outSequenceNumber, strm.avail_in);
- return (NULL);
- }
+ /*
+ * < 0 - fatal error;
+ * 0 - OK (no error at all);
+ * 1 - first block of ignored trailing garbage;
+ * 2 - error already signalled for earlier block
+ */
+ errState = decompressErrCheck(bzret, fileData, outSequenceNumber, strm);
+
if (bzret == BZ_STREAM_END)
{
- if (!(fileData->isLastInSequence))
- {
- handle_error(EF_EXIT, -1, "pbzip2: *ERROR on decompress - """
- "in segments for stream ended but BZ_STREAM_END not reached: ret=%d; block=%d; seq=%d\n",
- bzret, fileData->blockNumber, outSequenceNumber);
- return (NULL);
- }
-
bzret = BZ2_bzDecompressEnd(&strm);
- if (bzret != BZ_OK)
+ if ( (bzret != BZ_OK) && ((errState == 0) || (errState == 1)) )
{
handle_error(EF_EXIT, -1, "pbzip2: *ERROR during BZ2_bzDecompressEnd: %d\n", bzret);
return (NULL);
}
- outSequenceNumber = 0;
+ outSequenceNumber = -1;
prevOutBlockInSequence = NULL;
}
@@ -1200,6 +1608,14 @@
fflush(stderr);
#endif
+ if (errState != 0)
+ {
+ #ifdef PBZIP_DEBUG
+ fprintf (stderr, "consumer: exiting prematurely: errState=%d\n", errState);
+ #endif
+
+ return (NULL);
+ }
} // for
#ifdef PBZIP_DEBUG
@@ -1283,12 +1699,24 @@
(unsigned long long)lastnext);
#endif
+ if ( (LastGoodBlock != -1) && (NextBlockToWrite > LastGoodBlock) )
+ {
+ #ifdef PBZIP_DEBUG
+ fprintf (stderr, "fileWriter [b:%d]: quit - LastGoodBlock=%d\n",
+ currBlock, LastGoodBlock);
+ #endif
+ safe_mutex_unlock(OutMutex);
+
+ break;
+ }
+
if ((OutputBuffer[outBufferPos].buf == NULL) &&
((prevBlockInSequence == NULL) || (prevBlockInSequence->next == NULL)))
{
+ safe_cond_timed_wait(&OutBufferHeadNotEmpty, OutMutex, 1, "fileWriter");
safe_mutex_unlock(OutMutex);
// sleep a little so we don't go into a tight loop using up all the CPU
- usleep(50000);
+ // usleep(50000);
continue;
}
else
@@ -1358,6 +1786,7 @@
}
// --NumBufferedBlocks; // to be removed
safe_cond_broadcast(notTooMuchNumBuffered);
+ safe_cond_broadcast(&ErrStateChangeCond);
safe_mutex_unlock(OutMutex);
if (outBlock->sequenceNumber > 2)
@@ -1434,20 +1863,20 @@
}
safe_cond_broadcast(notTooMuchNumBuffered); // not really needed
- if (QuietMode != 1)
- {
- // print current completion status
- percentComplete = 100;
-
- #ifdef PBZIP_DEBUG
- fprintf(stderr, "Completed: %d%% NextBlockToWrite: %d/%u \r", percentComplete, NextBlockToWrite, NumBufferedBlocksMax);
+ if (QuietMode != 1)
+ {
+ // print current completion status
+ percentComplete = 100;
+
+ #ifdef PBZIP_DEBUG
+ fprintf(stderr, "Completed: %d%% NextBlockToWrite: %d/%u \r", percentComplete, NextBlockToWrite, NumBufferedBlocksMax);
+ fflush(stderr);
+ #else
+
+ fprintf(stderr, "Completed: %d%% \r", percentComplete);
fflush(stderr);
- #else
-
- fprintf(stderr, "Completed: %d%% \r", percentComplete);
- fflush(stderr);
- #endif
- }
+ #endif
+ }
return (NULL);
}
@@ -1717,7 +2146,13 @@
// see if we are outputting to stdout
if (OutputStdOut == 0)
{
- stream = fopen(OutFilename, "wb");
+ stream = fopen(OutFilename, "wb");
+ if (stream == NULL)
+ {
+ handle_error(EF_NOQUIT, -1,
+ "pbzip2: *ERROR: Could not open output file [%s]! Aborting...\n", OutFilename);
+ return -1;
+ }
}
else
{
@@ -2248,10 +2683,7 @@
q->size = queueSize;
- q->empty = 1;
- q->full = 0;
- q->head = 0;
- q->tail = 0;
+ q->clear();
q->mut = NULL;
q->mut = new(std::nothrow) pthread_mutex_t;
@@ -2365,11 +2797,36 @@
safe_mutex_unlock(OutMutex);
}
+/**
+ * Get output buffer index corresponding to the given absolute blockNumber
+ * (buffer is used in circular mode)
+ *
+ * @param blockNum - absolute block number to translate
+ * @return 0-based Output Buffer index where blockNum data should go
+ */
+inline size_t getOutputBufferPos(int blockNum)
+{
+ // calculate output buffer position (used in circular mode)
+ size_t outBuffPos = OutBufferPosToWrite + blockNum - NextBlockToWrite;
+
+ if (outBuffPos >= NumBufferedBlocksMax)
+ {
+ outBuffPos -= NumBufferedBlocksMax;
+ }
+
+ return outBuffPos;
+}
+
+/**
+ * Add next element to the given out buffer tail.
+ *
+ */
outBuff * outputBufferSeqAddNext(outBuff * preveElement, outBuff * newElement)
{
safe_mutex_lock(OutMutex);
- while (NumBufferedTailBlocks >= NumBufferedBlocksMax)
+ while ((NumBufferedTailBlocks >= NumBufferedBlocksMax) &&
+ (preveElement->buf != NULL))
{
if (syncGetTerminateFlag() != 0)
{
@@ -2380,6 +2837,15 @@
return NULL;
}
+ if ( (LastGoodBlock != -1) && (LastGoodBlock < newElement->blockNumber) )
+ {
+ #ifdef PBZIP_DEBUG
+ fprintf (stderr, "%s: terminating3 - LastGoodBlock set\n", "consumer");
+ #endif
+ pthread_mutex_unlock(OutMutex);
+ return NULL;
+ }
+
#ifdef PBZIP_DEBUG
fprintf (stderr, "%s/outputBufferSeqAddNext: Throttling from FileWriter backlog: %d\n", "consumer", NumBufferedBlocks);
#endif
@@ -2390,6 +2856,14 @@
++NumBufferedTailBlocks;
+ // size_t outBufPos = getOutputBufferPos(newElement->blockNumber);
+ if (preveElement->buf == NULL)
+ {
+ // fileWriter has already consumed the previous block. Let it know
+ // for that one early
+ safe_cond_signal(&OutBufferHeadNotEmpty);
+ }
+
safe_mutex_unlock(OutMutex);
return newElement;
@@ -2399,10 +2873,8 @@
* Store an item in OutputBuffer out bin. Synchronization is embedded to protect
* from simultaneous access.
*
- * @param in - item buffer
- * @param bufSize - item buffer size
- * @param blockNum - block number in the whole stream (not the position in buffer)
- * @param caller - calling function (used for logging and debug purposes)
+ * @param elem - output buffer element to add
+ * @param caller - used for debug purposes (caller function name)
*
* @return pointer to added element on success; NULL - on error
*/
@@ -2424,6 +2896,15 @@
return NULL;
}
+ if ( (LastGoodBlock != -1) && (LastGoodBlock < element.blockNumber) )
+ {
+ #ifdef PBZIP_DEBUG
+ fprintf (stderr, "%s: terminating3 - LastGoodBlock set\n", "consumer");
+ #endif
+ pthread_mutex_unlock(OutMutex);
+ return NULL;
+ }
+
#ifdef PBZIP_DEBUG
fprintf (stderr, "%s: Throttling from FileWriter backlog: %d\n", caller, NumBufferedBlocks);
#endif
@@ -2431,15 +2912,16 @@
}
// calculate output buffer position (used in circular mode)
- size_t outBuffPos = OutBufferPosToWrite + element.blockNumber - NextBlockToWrite;
- if (outBuffPos >= NumBufferedBlocksMax)
- {
- outBuffPos -= NumBufferedBlocksMax;
- }
+ size_t outBuffPos = getOutputBufferPos(element.blockNumber);
OutputBuffer[outBuffPos] = element;
++NumBufferedBlocks;
+ if (NextBlockToWrite == element.blockNumber)
+ {
+ safe_cond_signal(&OutBufferHeadNotEmpty);
+ }
+
safe_mutex_unlock(OutMutex);
return &(OutputBuffer[outBuffPos]);
@@ -2706,8 +3188,8 @@
*/
void banner()
{
- fprintf(stderr, "Parallel BZIP2 v1.1.1 - by: Jeff Gilchrist [http://compression.ca]\n");
- fprintf(stderr, "[Apr. 17, 2010] (uses libbzip2 by Julian Seward)\n");
+ fprintf(stderr, "Parallel BZIP2 v1.1.2 - by: Jeff Gilchrist [http://compression.ca]\n");
+ fprintf(stderr, "[Feb. 19, 2011] (uses libbzip2 by Julian Seward)\n");
fprintf(stderr, "Major contributions: Yavor Nikolov \n");
return;
@@ -2755,11 +3237,14 @@
fprintf(stderr, " -t,--test Test compressed file integrity\n");
fprintf(stderr, " -v,--verbose Verbose mode\n");
fprintf(stderr, " -V,--version Display version info for pbzip2 then exit\n");
- fprintf(stderr, " -z,--compress Compress file (default)\n\n");
+ fprintf(stderr, " -z,--compress Compress file (default)\n");
+ fprintf(stderr, " --ignore-trailing-garbage=# Ignore trailing garbage flag (1 - ignored; 0 - forbidden)\n");
+ fprintf(stderr, "\n");
fprintf(stderr, "Example: pbzip2 -b15vk myfile.tar\n");
fprintf(stderr, "Example: pbzip2 -p4 -r -5 myfile.tar second*.txt\n");
fprintf(stderr, "Example: tar cf myfile.tar.bz2 --use-compress-prog=pbzip2 dir_to_compress/\n");
- fprintf(stderr, "Example: pbzip2 -d -m500 myfile.tar.bz2\n\n");
+ fprintf(stderr, "Example: pbzip2 -d -m500 myfile.tar.bz2\n");
+ fprintf(stderr, "\n");
exit(-1);
}
@@ -2805,6 +3290,7 @@
int numBlocks = 0;
int blockSize = 9*100000;
int maxMemory = 100000000;
+ int maxMemorySwitch = 0;
int decompress = 0;
int compress = 0;
int testFile = 0;
@@ -2849,6 +3335,20 @@
{
decompress = OutputStdOut = keep = 1;
}
+
+ #ifdef IGNORE_TRAILING_GARBAGE
+ // default behavior is hard-coded (still dynamically changeable)
+ IgnoreTrailingGarbageFlag = IGNORE_TRAILING_GARBAGE;
+ #else
+ // default depends on program name
+ if ((strcmp(progName, "bzip2") == 0) || (strcmp(progName, "BZIP2") == 0) ||
+ (strcmp(progName, "bunzip2") == 0) || (strcmp(progName, "BUNZIP2") == 0) ||
+ (strcmp(progName, "bzcat") == 0) || (strcmp(progName, "BZCAT") == 0))
+ {
+ // Favour traditional non-parallel bzip2 behavior
+ IgnoreTrailingGarbageFlag = 1;
+ }
+ #endif // IGNORE_TRAILING_GARBAGE
FileListCount = 0;
FileList = new(std::nothrow) char *[argc];
@@ -2944,6 +3444,18 @@
{
banner(); exit(0);
}
+ else if (strcmp(argv[i], "--ignore-trailing-garbage") == 0 )
+ {
+ IgnoreTrailingGarbageFlag = 1;
+ }
+ else if (strcmp(argv[i], "--ignore-trailing-garbage=1") == 0 )
+ {
+ IgnoreTrailingGarbageFlag = 1;
+ }
+ else if (strcmp(argv[i], "--ignore-trailing-garbage=0") == 0 )
+ {
+ IgnoreTrailingGarbageFlag = 0;
+ }
continue;
}
@@ -3001,7 +3513,7 @@
blockSize = atoi(cmdLineTemp)*100000;
if ((blockSize < 100000) || (blockSize > 1000000000))
{
- fprintf(stderr,"pbzip2: *ERROR: File block size Min: 100k and Max: 10000k! Aborting...\n");
+ fprintf(stderr,"pbzip2: *ERROR: File block size Min: 100k and Max: 1000000k! Aborting...\n");
return 1;
}
j += cmdLineTempCount;
@@ -3023,11 +3535,12 @@
strncpy(cmdLineTemp, argv[i]+j+1, cmdLineTempCount);
cmdLineTemp[cmdLineTempCount] = '\0';
maxMemory = atoi(cmdLineTemp)*1000000;
- if ((maxMemory < 1000000) || (maxMemory > 1000000000))
+ if ((maxMemory < 1000000) || (maxMemory > 2000000000))
{
- fprintf(stderr,"pbzip2: *ERROR: Memory usage size Min: 1MB and Max: 1000MB! Aborting...\n");
+ fprintf(stderr,"pbzip2: *ERROR: Memory usage size Min: 1MB and Max: 2000MB! Aborting...\n");
return 1;
}
+ maxMemorySwitch = 1;
j += cmdLineTempCount;
#ifdef PBZIP_DEBUG
fprintf(stderr, "-m%d\n", maxMemory);
@@ -3285,6 +3798,12 @@
if (ChildThreadStackSize > 0)
fprintf(stderr, " Stack Size: %d KB\n", ChildThreadStackSize/1024);
#endif
+
+ if (decompress == 1)
+ {
+ fprintf(stderr, " Ignore Trailng Garbage: %s\n",
+ (IgnoreTrailingGarbageFlag == 1) ? "on" : "off" );
+ }
}
fprintf(stderr, "-------------------------------------------\n");
}
@@ -3647,6 +4166,24 @@
fprintf(stderr, "pbzip2: maxMemory: %d blockSize: %d\n", maxMemory, blockSize);
fprintf(stderr, "pbzip2: NumBufferedBlocksMax: %u\n", NumBufferedBlocksMax);
#endif
+ // check to see if our max buffered blocks is less than numCPU, if yes increase maxMemory
+ // to support numCPU requested unless -m switch given by user
+ if (NumBufferedBlocksMax < (size_t)numCPU)
+ {
+ if (maxMemorySwitch == 0)
+ {
+ NumBufferedBlocksMax = numCPU;
+ if (QuietMode != 1)
+ fprintf(stderr, "*Warning* Max memory limit increased to %d MB to support %d CPUs\n", ((NumBufferedBlocksMax + (numCPU * 2)) * blockSize)/1000000, numCPU);
+ }
+ else
+ {
+ if (QuietMode != 1)
+ fprintf(stderr, "*Warning* CPU usage and performance may be suboptimal due to max memory limit.\n");
+ }
+ }
+
+ LastGoodBlock = -1;
// create output buffer
outputBufferInit(NumBufferedBlocksMax);
@@ -3777,6 +4314,11 @@
}
}
+ if (syncGetTerminateFlag() != 0)
+ {
+ errLevel = 1;
+ }
+
if (OutputStdOut == 0)
{
// write store file meta data to output file
@@ -3806,10 +4348,7 @@
// reclaim memory
OutputBuffer.clear();
- fifo->empty = 1;
- fifo->full = 0;
- fifo->head = 0;
- fifo->tail = 0;
+ fifo->clear();
if (QuietMode != 1)
fprintf(stderr, "-------------------------------------------\n");
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pbzip2-1.1.1/pbzip2.h new/pbzip2-1.1.2/pbzip2.h
--- old/pbzip2-1.1.1/pbzip2.h 2010-04-17 20:37:39.000000000 +0200
+++ new/pbzip2-1.1.2/pbzip2.h 2011-02-19 11:10:22.000000000 +0100
@@ -3,6 +3,11 @@
* Author: Yavor Nikolov
*
* Created on March 6, 2010, 10:18 PM
+ *
+ * Change History:
+ * 2010-05-20 - by Yavor Nikolov
+ * - Transformed input queue as queue of queues to avoid deadlock and conten
+ * tion issues.
*/
#ifndef _PBZIP2_H
@@ -47,6 +52,7 @@
#endif
#include
+#include
}
// uncomment for debug output
@@ -89,6 +95,7 @@
unsigned int inSize; // original size before compression/decompressoin
bool isLastInSequence;
outBuff * next; // next in longer sequence of buffers for this block
+ //outBuff * last; // last in sequence (here as quick hack since global one would be enough)
outBuff(
char * aBuf = NULL,
@@ -104,7 +111,8 @@
sequenceNumber(aSequenceNumber),
inSize(aInSize),
isLastInSequence(isLast),
- next(aNext)
+ next(aNext)//,
+ //last(NULL)
{}
} outBuff;
@@ -122,20 +130,72 @@
ElementTypePtr *qData;
long size;
+ long count; // actual element count, including tail-queue ones
long head, tail;
int full, empty;
+ int topLevelFull, topLevelEmpty;
pthread_mutex_t *mut;
pthread_cond_t *notFull, *notEmpty;
pthread_t *consumers;
+ ElementTypePtr lastElement; // most recently added element
+
+ queue(): count(0), lastElement(NULL)
+ {}
+
+ /**
+ * Reset the queue putting it to initial empty state.
+ */
+ void clear()
+ {
+ empty = 1;
+ full = 0;
+ head = 0;
+ tail = 0;
+ count = 0;
+ lastElement = NULL;
+ topLevelFull = 0;
+ topLevelEmpty = 1;
+ }
void add(ElementTypePtr element)
{
- qData[tail] = element;
- ++tail;
+ #ifdef PBZIP_DEBUG
+ fprintf (stderr, "queue::add: elem=%llx\n",
+ (unsigned long long)element);
+
+ if (element != NULL)
+ {
+ fprintf (stderr, " queue::add: seq=%d; blk=%d; islast=%d\n",
+ element->sequenceNumber,
+ element->blockNumber,
+ (int)element->isLastInSequence);
+ }
+ #endif
+
+ if ( element->sequenceNumber > 1 )
+ {
+ // multi-part sequence: append to same one
+ lastElement->next = element;
+ }
+ else
+ {
+ // primary element (either first in sequence; or a standalone one)
+ qData[tail] = element;
+ ++tail;
+
+ if (tail == size)
+ tail = 0;
+
+ if (tail == head)
+ topLevelFull = 1;
- if (tail == size)
- tail = 0;
- if (tail == head)
+ topLevelEmpty = 0;
+ }
+
+ lastElement = element;
+ ++count;
+
+ if (count == size)
full = 1;
empty = 0;
@@ -143,6 +203,7 @@
/**
* Remove the head returning it into element. If the given element is
+ * tail of multi-segment sequence - just moves to next segment.
*
* @param element - removed element is copied here
* @return 1 on success; 0 - on denied request; -1 - on error
@@ -152,33 +213,62 @@
ElementTypePtr & headElem = qData[head];
#ifdef PBZIP_DEBUG
- fprintf (stderr, "queue::remove: head=%llx; elem=%llx\n",
+ fprintf (stderr, "queue::remove: head=%llx; elem=%llx; count=%ld\n",
(unsigned long long)headElem,
- (unsigned long long)element);
+ (unsigned long long)element,
+ count);
if (headElem != NULL)
{
- fprintf (stderr, " queue::remove: head: seq=%d; blk=%d; islast=%d\n",
+ fprintf (stderr, " queue::remove: head: seq=%d; blk=%d; islast=%d\n",
headElem->sequenceNumber,
headElem->blockNumber,
(int)headElem->isLastInSequence);
}
+
+ if (element != NULL)
+ {
+ fprintf (stderr, " queue::remove: element: seq=%d; blk=%d; islast=%d\n",
+ element->sequenceNumber,
+ element->blockNumber,
+ (int)element->isLastInSequence);
+ }
#endif
- if ((headElem->sequenceNumber > 1) &&
- ((element == NULL) || (headElem->blockNumber != element->blockNumber)))
+ if ( (element != NULL) && !element->isLastInSequence )
+ {
+ if (element->next != NULL)
+ {
+ element = element->next;
+ }
+ else
+ {
+ // 2+ part of long-sequence BZ2 stream. Next
+ // segment is not ready yet.
+ return 0;
+ }
+ }
+ else if (topLevelEmpty)
{
- // 2+ part of long-sequence BZ2 stream. Deny if requestor is not
- // aware of that
return 0;
}
+ else
+ {
+ element = headElem;
+ ++head;
+
+ if (head == size)
+ head = 0;
- element = headElem;
- ++head;
+ if (head == tail)
+ topLevelEmpty = 1;
+
+ topLevelFull = 0;
+ }
- if (head == size)
- head = 0;
- if (head == tail)
+ --count;
+
+ if (count == 0)
empty = 1;
full = 0;
@@ -226,6 +316,19 @@
}
}
+/**
+ * Dispose the given buffer memory if not NULL and make it NULL. Provided
+ * buffer should be allocated with new.
+ */
+template <typename C>
+inline void disposeMemorySingle(C *& pBuff)
+{
+ if (pBuff != NULL)
+ {
+ delete pBuff;
+ pBuff = NULL;
+ }
+}
/**
* Check if a given string ends with a given suffix ignoring case difference.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pbzip2-1.1.1/pbzip2.spec new/pbzip2-1.1.2/pbzip2.spec
--- old/pbzip2-1.1.1/pbzip2.spec 2010-04-17 20:37:39.000000000 +0200
+++ new/pbzip2-1.1.2/pbzip2.spec 2011-02-19 11:10:22.000000000 +0100
@@ -1,5 +1,5 @@
Name: pbzip2
-Version: 1.1.1
+Version: 1.1.2
Release: 1%{?dist}
Summary: Parallel implementation of bzip2
URL: http://www.compression.ca/pbzip2/
@@ -52,6 +52,9 @@
%changelog
+* Sat Feb 19 2011 Jeff Gilchrist - 1.1.2-1
+- Release 1.1.2
+
* Sat Apr 17 2010 Jeff Gilchrist - 1.1.1-1
- Release 1.1.1
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Remember to have fun...
--
To unsubscribe, e-mail: opensuse-commit+unsubscribe@opensuse.org
For additional commands, e-mail: opensuse-commit+help@opensuse.org