Skip to content

Commit 6719a67

Browse files
authored
Bump par2-turbo to v1.4.0-20260803, pass -T flag, and clamp stage progress (#885)
- Updated `par2-turbo` to `v1.4.0-20260803`. - Added `-T` flag matching `-t` count in `ParChecker.cpp` to enable multi-threaded file verification. - Clamped `m_stageProgress` to `[0, 1000]` permille in `ParChecker` and `DownloadInfo` to prevent concurrent verification progress overflow > 100, fixing the `-1s` ETA issue in WebUI. - Cleaned up C-style casts.
1 parent 7fa6bc0 commit 6719a67

4 files changed

Lines changed: 69 additions & 59 deletions

File tree

cmake/par2-turbo.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ ExternalProject_add(
5757
par2-turbo
5858
PREFIX par2-turbo
5959
GIT_REPOSITORY https://github.com/nzbgetcom/par2cmdline-turbo.git
60-
GIT_TAG v1.4.0-20260323
60+
GIT_TAG v1.4.0-20260803
6161
TLS_VERIFY TRUE
6262
GIT_SHALLOW TRUE
6363
GIT_PROGRESS TRUE

daemon/postprocess/ParChecker.cpp

Lines changed: 41 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
#include <vector>
2727
#include <string>
28+
#include <algorithm>
2829

2930
#include <par2/libpar2.h>
3031
#include <par2/commandline.h>
@@ -36,7 +37,7 @@
3637
#include "Util.h"
3738
#include "FileSystem.h"
3839

39-
const char* Par2CmdLineErrStr[] = {
40+
static const char* Par2CmdLineErrStr[] = {
4041
"OK",
4142
"data files are damaged and there is enough recovery data available to repair them",
4243
"data files are damaged and there is insufficient recovery data available to be able to repair them",
@@ -48,7 +49,7 @@ const char* Par2CmdLineErrStr[] = {
4849
"out of memory"
4950
};
5051

51-
const char* Par2StageMessage[] = {
52+
static const char* Par2StageMessage[] = {
5253
"Loading file",
5354
"Verifying file",
5455
"Repairing file",
@@ -73,7 +74,7 @@ class Repairer final : public Par2::Par2Repairer, public ParChecker::AbstractRep
7374
}
7475
Par2::Result PreProcess(const std::string& parFilename);
7576
Par2::Result Process(bool dorepair);
76-
virtual Repairer* GetRepairer() { return this; }
77+
Repairer* GetRepairer() override { return this; }
7778

7879
protected:
7980
void SigFilename(std::string filename) override { m_owner->SignalFilename(std::move(filename)); }
@@ -110,8 +111,10 @@ class RepairCreatorPacket : public Par2::CreatorPacket
110111

111112
Par2::Result Repairer::PreProcess(const std::string& parFilename)
112113
{
114+
std::string threadsStr = std::to_string(m_threadsToUse);
113115
std::string memParam = "-m" + std::to_string(m_memToUse);
114-
std::string threadsParam = "-t" + std::to_string(m_threadsToUse);
116+
std::string threadsParam = "-t" + threadsStr;
117+
std::string fileThreadsParam = "-T" + threadsStr;
115118

116119
if (g_Options->GetParScan() == Options::psFull)
117120
{
@@ -123,16 +126,16 @@ Par2::Result Repairer::PreProcess(const std::string& parFilename)
123126
basename[1] = '\0';
124127
}
125128

126-
const char* argv[] = { "par2", "r", "-v", memParam.c_str(), threadsParam.c_str(), parFilename.c_str(), wildcardParam };
127-
if (!m_commandLine.Parse(7, (char**)argv))
129+
const char* argv[] = { "par2", "r", "-v", memParam.c_str(), threadsParam.c_str(), fileThreadsParam.c_str(), parFilename.c_str(), wildcardParam };
130+
if (!m_commandLine.Parse(8, const_cast<char**>(argv)))
128131
{
129132
return Par2::eInvalidCommandLineArguments;
130133
}
131134
}
132135
else
133136
{
134-
const char* argv[] = { "par2", "r", "-v", memParam.c_str(), threadsParam.c_str(), parFilename.c_str() };
135-
if (!m_commandLine.Parse(6, (char**)argv))
137+
const char* argv[] = { "par2", "r", "-v", memParam.c_str(), threadsParam.c_str(), fileThreadsParam.c_str(), parFilename.c_str() };
138+
if (!m_commandLine.Parse(7, const_cast<char**>(argv)))
136139
{
137140
return Par2::eInvalidCommandLineArguments;
138141
}
@@ -179,11 +182,11 @@ bool Repairer::ScanDataFile(
179182

180183
if (!(m_owner->GetStage() == ParChecker::ptVerifyingRepaired && m_owner->GetParFull()))
181184
{
182-
int availableBlocks = sourcefile->BlockCount();
185+
int availableBlocks = static_cast<int>(sourcefile->BlockCount());
183186
ParChecker::EFileStatus fileStatus = m_owner->VerifyDataFile(*diskfile, *sourcefile, availableBlocks);
184187
if (fileStatus != ParChecker::fsUnknown)
185188
{
186-
SigDone(name, availableBlocks, sourcefile->BlockCount());
189+
SigDone(name, availableBlocks, static_cast<int>(sourcefile->BlockCount()));
187190
SigProgress(1000);
188191
matchtype = fileStatus == ParChecker::fsSuccess ? Par2::eFullMatch :
189192
fileStatus == ParChecker::fsPartial ? Par2::ePartialMatch : Par2::eNoMatch;
@@ -206,8 +209,8 @@ bool Repairer::ScanDataFile(
206209

207210
void Repairer::BeginRepair()
208211
{
209-
m_owner->PrintMessage(Message::mkInfo, "Using %i thread(s) and %i MB to repair %i block(s) for %s",
210-
m_threadsToUse, m_memToUse, (int)missingblockcount, m_owner->m_nzbName.c_str());
212+
m_owner->PrintMessage(Message::mkInfo, "Using %i thread(s) and %i MB to repair %u block(s) for %s",
213+
m_threadsToUse, m_memToUse, missingblockcount, m_owner->m_nzbName.c_str());
211214
}
212215

213216
int ParChecker::StreamBuf::overflow(int ch)
@@ -387,7 +390,7 @@ ParChecker::EStatus ParChecker::RunParCheck(std::string parFilename)
387390

388391
if (m_hasDamagedFiles && !IsStopped() && res == Par2::eRepairNotPossible)
389392
{
390-
res = (Par2::Result)ProcessMorePars();
393+
res = static_cast<Par2::Result>(ProcessMorePars());
391394
}
392395

393396
if (m_hasDamagedFiles && !IsStopped() && res == Par2::eRepairNotPossible &&
@@ -398,7 +401,7 @@ ParChecker::EStatus ParChecker::RunParCheck(std::string parFilename)
398401
res = GetRepairer()->Process(false);
399402
if (!IsStopped() && res == Par2::eRepairNotPossible)
400403
{
401-
res = (Par2::Result)ProcessMorePars();
404+
res = static_cast<Par2::Result>(ProcessMorePars());
402405
}
403406
}
404407
}
@@ -429,7 +432,7 @@ ParChecker::EStatus ParChecker::RunParCheck(std::string parFilename)
429432
m_stageProgress = 0;
430433
m_processedCount = 0;
431434
m_stage = ptRepairing;
432-
m_filesToRepair = GetRepairer()->damagedfilecount + GetRepairer()->missingfilecount;
435+
m_filesToRepair = static_cast<int>(GetRepairer()->damagedfilecount + GetRepairer()->missingfilecount);
433436
UpdateProgress();
434437

435438
res = GetRepairer()->Process(true);
@@ -468,7 +471,7 @@ ParChecker::EStatus ParChecker::RunParCheck(std::string parFilename)
468471
}
469472
else if (status == psFailed)
470473
{
471-
if (m_errMsg.empty() && (int)res >= 0 && (int)res <= 8)
474+
if (m_errMsg.empty() && static_cast<int>(res) >= 0 && static_cast<int>(res) <= 8)
472475
{
473476
m_errMsg = Par2CmdLineErrStr[res];
474477
}
@@ -593,8 +596,7 @@ int ParChecker::ProcessMorePars()
593596
bool moreFilesLoaded = true;
594597
while (!IsStopped() && res == Par2::eRepairNotPossible)
595598
{
596-
int missingblockcount = GetRepairer()->missingblockcount -
597-
GetRepairer()->recoverypacketmap.size();
599+
int missingblockcount = static_cast<int>(GetRepairer()->missingblockcount - GetRepairer()->recoverypacketmap.size());
598600
if (missingblockcount <= 0)
599601
{
600602
return Par2::eRepairPossible;
@@ -754,7 +756,7 @@ bool ParChecker::AddSplittedFragments()
754756
bool ParChecker::MaybeSplittedFragement(const char* filename1, const char* filename2)
755757
{
756758
// check if name is same but the first name has additional numerical extension
757-
int len = strlen(filename2);
759+
size_t len = strlen(filename2);
758760
if (!strncasecmp(filename1, filename2, len))
759761
{
760762
const char* p = filename1 + len;
@@ -803,24 +805,24 @@ bool ParChecker::AddDupeFiles()
803805

804806
if (!m_dupeSources.empty())
805807
{
806-
int wasBlocksMissing = GetRepairer()->missingblockcount;
808+
uint32_t wasBlocksMissing = GetRepairer()->missingblockcount;
807809

808810
for (DupeSource& dupeSource : m_dupeSources)
809811
{
810812
if (GetRepairer()->missingblockcount > 0 && FileSystem::DirectoryExists(dupeSource.GetDirectory()))
811813
{
812-
int wasBlocksMissing2 = GetRepairer()->missingblockcount;
814+
uint32_t wasBlocksMissing2 = GetRepairer()->missingblockcount;
813815
bool oneAdded = AddExtraFiles(false, true, dupeSource.GetDirectory());
814816
added |= oneAdded;
815-
int blocksMissing2 = GetRepairer()->missingblockcount;
816-
dupeSource.SetUsedBlocks(dupeSource.GetUsedBlocks() + (wasBlocksMissing2 - blocksMissing2));
817+
uint32_t blocksMissing2 = GetRepairer()->missingblockcount;
818+
dupeSource.SetUsedBlocks(dupeSource.GetUsedBlocks() + static_cast<int>((wasBlocksMissing2 - blocksMissing2)));
817819
}
818820
}
819821

820-
int blocksMissing = GetRepairer()->missingblockcount;
822+
uint32_t blocksMissing = GetRepairer()->missingblockcount;
821823
if (blocksMissing < wasBlocksMissing)
822824
{
823-
PrintMessage(Message::mkInfo, "Found extra %i blocks in dupe sources", wasBlocksMissing - blocksMissing);
825+
PrintMessage(Message::mkInfo, "Found extra %u blocks in dupe sources", wasBlocksMissing - blocksMissing);
824826
}
825827
else
826828
{
@@ -906,14 +908,14 @@ bool ParChecker::AddExtraFiles(bool onlyMissing, bool externalDir, const char* d
906908
const std::string& extraFile = extrafiles[idx];
907909
++idx;
908910

909-
int wasFilesMissing = GetRepairer()->missingfilecount;
910-
int wasBlocksMissing = GetRepairer()->missingblockcount;
911+
uint32_t wasFilesMissing = GetRepairer()->missingfilecount;
912+
uint32_t wasBlocksMissing = GetRepairer()->missingblockcount;
911913

912914
GetRepairer()->VerifyExtraFiles({ extraFile }, m_destDir, false);
913915
GetRepairer()->UpdateVerificationResults();
914916

915-
bool fileAdded = wasFilesMissing > (int)GetRepairer()->missingfilecount;
916-
bool blockAdded = wasBlocksMissing > (int)GetRepairer()->missingblockcount;
917+
bool fileAdded = wasFilesMissing > GetRepairer()->missingfilecount;
918+
bool blockAdded = wasBlocksMissing > GetRepairer()->missingblockcount;
917919

918920
if (fileAdded && !externalDir)
919921
{
@@ -922,7 +924,7 @@ bool ParChecker::AddExtraFiles(bool onlyMissing, bool externalDir, const char* d
922924
}
923925
else if (blockAdded)
924926
{
925-
PrintMessage(Message::mkInfo, "Found %i missing blocks", wasBlocksMissing - (int)GetRepairer()->missingblockcount);
927+
PrintMessage(Message::mkInfo, "Found %u missing blocks", wasBlocksMissing - GetRepairer()->missingblockcount);
926928
}
927929

928930
filesAdded |= fileAdded | blockAdded;
@@ -1011,7 +1013,7 @@ void ParChecker::SignalProgress(int progress)
10111013
else
10121014
{
10131015
// verifying individual files
1014-
totalFiles = GetRepairer()->sourcefiles.size() + m_extraFiles;
1016+
totalFiles = static_cast<int>(GetRepairer()->sourcefiles.size()) + m_extraFiles;
10151017
if (m_extraFiles > 0)
10161018
{
10171019
// during extra par scan don't count quickly verified files;
@@ -1041,6 +1043,8 @@ void ParChecker::SignalProgress(int progress)
10411043

10421044
debug("Current-progress: %i, Total-progress: %i", m_fileProgress, m_stageProgress);
10431045

1046+
m_stageProgress = std::clamp(m_stageProgress, 0, 1000);
1047+
10441048
UpdateProgress();
10451049
}
10461050

@@ -1115,8 +1119,8 @@ void ParChecker::CheckEmptyFiles()
11151119
bool ignore = Util::MatchFileExt(filenameObj.c_str(), g_Options->GetParIgnoreExt(), ",;");
11161120
m_hasDamagedFiles |= !ignore;
11171121

1118-
int total = sourcefile->GetVerificationPacket() ? sourcefile->GetVerificationPacket()->BlockCount() : 0;
1119-
PrintMessage(Message::mkWarning, "File %s has %i bad block(s) of total %i block(s)%s",
1122+
uint32_t total = sourcefile->GetVerificationPacket() ? sourcefile->GetVerificationPacket()->BlockCount() : 0;
1123+
PrintMessage(Message::mkWarning, "File %s has %u bad block(s) of total %u block(s)%s",
11201124
filenameObj.c_str(), total, total, ignore ? ", ignoring" : "");
11211125
}
11221126
}
@@ -1151,7 +1155,7 @@ void ParChecker::SaveSourceList()
11511155
}
11521156

11531157
std::vector<Par2::DataBlock>::iterator it2 = sourcefile->SourceBlocks();
1154-
for (int i = 0; i < (int)sourcefile->BlockCount(); i++, it2++)
1158+
for (uint32_t i = 0; i < sourcefile->BlockCount(); ++i, ++it2)
11551159
{
11561160
Par2::DataBlock block = *it2;
11571161
Par2::DiskFile* sourceFile = block.GetDiskFile();
@@ -1293,14 +1297,14 @@ ParChecker::EFileStatus ParChecker::VerifyDataFile(Par2::DiskFile& diskFile, Par
12931297
return fileStatus;
12941298
}
12951299

1296-
bool ParChecker::VerifySuccessDataFile(Par2::DiskFile& diskFile, Par2::Par2RepairerSourceFile& sourceFile, uint32 downloadCrc)
1300+
bool ParChecker::VerifySuccessDataFile(Par2::DiskFile&, Par2::Par2RepairerSourceFile& sourceFile, uint32 downloadCrc)
12971301
{
12981302
Par2::u64 blocksize = GetRepairer()->mainpacket->BlockSize();
12991303
Par2::VerificationPacket* packet = sourceFile.GetVerificationPacket();
13001304

13011305
// extend lDownloadCrc to block size
13021306
downloadCrc = Par2::CRCUpdateBlock(downloadCrc ^ 0xFFFFFFFF,
1303-
(size_t)(blocksize * packet->BlockCount() > sourceFile.GetTargetFile()->FileSize() ?
1307+
(blocksize * packet->BlockCount() > sourceFile.GetTargetFile()->FileSize() ?
13041308
blocksize * packet->BlockCount() - sourceFile.GetTargetFile()->FileSize() : 0)
13051309
) ^ 0xFFFFFFFF;
13061310
debug("Download-CRC: %.8x", downloadCrc);
@@ -1319,7 +1323,7 @@ bool ParChecker::VerifySuccessDataFile(Par2::DiskFile& diskFile, Par2::Par2Repai
13191323
return parCrc == downloadCrc;
13201324
}
13211325

1322-
bool ParChecker::VerifyPartialDataFile(Par2::DiskFile& diskFile, Par2::Par2RepairerSourceFile& sourceFile, SegmentList& segments, ValidBlocks& validBlocks)
1326+
bool ParChecker::VerifyPartialDataFile(Par2::DiskFile&, Par2::Par2RepairerSourceFile& sourceFile, SegmentList& segments, ValidBlocks& validBlocks)
13231327
{
13241328
Par2::VerificationPacket* packet = sourceFile.GetVerificationPacket();
13251329
int64 blocksize = GetRepairer()->mainpacket->BlockSize();

daemon/postprocess/ParChecker.h

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@
3030

3131
#include <par2/par2repairer.h>
3232

33-
#include "NString.h"
34-
#include "Container.h"
3533
#include "FileSystem.h"
3634
#include "Log.h"
3735

@@ -61,7 +59,7 @@ class ParChecker
6159
class AbstractRepairer
6260
{
6361
public:
64-
virtual ~AbstractRepairer() {};
62+
virtual ~AbstractRepairer() = default;
6563
virtual Repairer* GetRepairer() = 0;
6664
};
6765

@@ -120,8 +118,8 @@ class ParChecker
120118

121119
private:
122120
int m_id;
123-
std::string m_directory;
124121
int m_usedBlocks = 0;
122+
std::string m_directory;
125123
};
126124

127125
typedef std::deque<DupeSource> DupeSourceList;
@@ -141,7 +139,7 @@ class ParChecker
141139
*/
142140
virtual bool RequestMorePars(int blockNeeded, int* blockFound) = 0;
143141
virtual void UpdateProgress() {}
144-
virtual bool IsStopped() { return false; };
142+
virtual bool IsStopped() { return false; }
145143
virtual void Completed() {}
146144
virtual void PrintMessage([[maybe_unused]] Message::EKind kind,
147145
[[maybe_unused]] const char* format, ...) PRINTF_SYNTAX(3) {}
@@ -158,42 +156,39 @@ class ParChecker
158156
int GetStageProgress() { return m_stageProgress; }
159157

160158
private:
161-
class StreamBuf : public std::streambuf
159+
class StreamBuf final : public std::streambuf
162160
{
163161
public:
164162
StreamBuf(ParChecker* owner, Message::EKind kind) : m_owner(owner), m_kind(kind) {}
165163
virtual int overflow(int ch) override;
166164
private:
165+
std::string m_buffer;
167166
ParChecker* m_owner;
168167
Message::EKind m_kind;
169-
std::string m_buffer;
170168
};
171169

172170
typedef std::deque<std::string> FileList;
173171
typedef std::deque<Par2::DiskFile*> SourceList;
174172
typedef std::vector<bool> ValidBlocks;
175173

176-
bool m_queuedParFilesChanged;
177-
bool m_verifyingExtraFiles;
178-
bool m_cancelled;
179-
bool m_hasDamagedFiles;
180-
bool m_forceRepair = false;
181-
int m_processedCount;
182-
int m_filesToRepair;
183-
int m_extraFiles;
184-
int m_fileProgress;
185-
int m_stageProgress;
186-
std::atomic<bool> m_parQuick{false};
187-
std::atomic<bool> m_parFull{false};
188-
std::atomic<int> m_quickFiles{0};
189174
std::string m_infoName;
190175
std::string m_destDir;
191176
std::string m_nzbName;
192177
std::string m_parFilename;
193178
std::string m_progressLabel;
194179
std::string m_errMsg;
180+
181+
int m_processedCount;
182+
int m_filesToRepair;
183+
int m_extraFiles;
184+
int m_fileProgress;
185+
int m_stageProgress;
186+
195187
EStatus m_status = psFailed;
188+
196189
std::atomic<EStage> m_stage{ptLoadingPars};
190+
std::atomic<int> m_quickFiles{0};
191+
197192
FileList m_queuedParFiles;
198193
FileList m_processedFiles;
199194
SourceList m_sourceFiles;
@@ -209,6 +204,16 @@ class ParChecker
209204
// "m_repairer" should be of type "Par2::Par2Repairer", however to prevent the
210205
// including of libpar2-headers into this header-file we use an empty abstract class.
211206
std::unique_ptr<AbstractRepairer> m_repairer;
207+
208+
std::atomic<bool> m_parQuick{false};
209+
std::atomic<bool> m_parFull{false};
210+
211+
bool m_queuedParFilesChanged;
212+
bool m_verifyingExtraFiles;
213+
bool m_cancelled;
214+
bool m_hasDamagedFiles;
215+
bool m_forceRepair = false;
216+
212217
Repairer* GetRepairer() { return m_repairer->GetRepairer(); }
213218

214219
void Cleanup();

0 commit comments

Comments
 (0)