added the automatic cleaning up of the download queue (deletion of unneeded paused par-files) after successful par-check/repair - new option <ParCleanupQueue>

This commit is contained in:
Andrey Prygunkov
2008-02-05 18:10:02 +00:00
parent 984f8b2dd9
commit ea05d5635a
5 changed files with 165 additions and 35 deletions

View File

@@ -1,5 +1,5 @@
/*
* This file if part of nzbget
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
@@ -132,6 +132,7 @@ static const char* OPTION_DIRECTWRITE = "DirectWrite";
static const char* OPTION_WRITEBUFFERSIZE = "WriteBufferSize";
static const char* OPTION_NZBDIRINTERVAL = "NzbDirInterval";
static const char* OPTION_NZBDIRFILEAGE = "NzbDirFileAge";
static const char* OPTION_PARCLEANUPQUEUE = "ParCleanupQueue";
#ifndef WIN32
const char* PossibleConfigLocations[] =
@@ -212,6 +213,7 @@ Options::Options(int argc, char* argv[])
m_iWriteBufferSize = 0;
m_iNzbDirInterval = 0;
m_iNzbDirFileAge = 0;
m_bParCleanupQueue = false;
char szFilename[MAX_PATH + 1];
#ifdef WIN32
@@ -403,6 +405,7 @@ void Options::InitDefault()
SetOption(OPTION_WRITEBUFFERSIZE, "0");
SetOption(OPTION_NZBDIRINTERVAL, "5");
SetOption(OPTION_NZBDIRFILEAGE, "60");
SetOption(OPTION_PARCLEANUPQUEUE, "no");
}
void Options::InitOptFile()
@@ -543,6 +546,7 @@ void Options::InitOptions()
m_bCrcCheck = (bool)ParseOptionValue(OPTION_CRCCHECK, BoolCount, BoolNames, BoolValues);
m_bRetryOnCrcError = (bool)ParseOptionValue(OPTION_RETRYONCRCERROR, BoolCount, BoolNames, BoolValues);
m_bDirectWrite = (bool)ParseOptionValue(OPTION_DIRECTWRITE, BoolCount, BoolNames, BoolValues);
m_bParCleanupQueue = (bool)ParseOptionValue(OPTION_PARCLEANUPQUEUE, BoolCount, BoolNames, BoolValues);
const char* OutputModeNames[] = { "loggable", "logable", "log", "colored", "color", "ncurses", "curses" };
const int OutputModeValues[] = { omLoggable, omLoggable, omLoggable, omColored, omColored, omNCurses, omNCurses };

View File

@@ -1,5 +1,5 @@
/*
* This file if part of nzbget
* This file is part of nzbget
*
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
@@ -133,6 +133,7 @@ private:
int m_iWriteBufferSize;
int m_iNzbDirInterval;
int m_iNzbDirFileAge;
bool m_bParCleanupQueue;
// Parsed command-line parameters
bool m_bServerMode;
@@ -224,6 +225,7 @@ public:
int GetWriteBufferSize() { return m_iWriteBufferSize; }
int GetNzbDirInterval() { return m_iNzbDirInterval; }
int GetNzbDirFileAge() { return m_iNzbDirFileAge; }
bool GetParCleanupQueue() { return m_bParCleanupQueue; }
// Parsed command-line parameters
bool GetServerMode() { return m_bServerMode; }

View File

@@ -89,6 +89,7 @@ PrePostProcessor::PrePostProcessor()
g_pQueueCoordinator->Attach(&m_QueueCoordinatorObserver);
m_ParQueue.clear();
m_FailedParJobs.clear();
#ifndef DISABLE_PARCHECK
m_ParCheckerObserver.owner = this;
@@ -104,6 +105,11 @@ PrePostProcessor::~PrePostProcessor()
{
delete *it;
}
for (FileList::iterator it = m_FailedParJobs.begin(); it != m_FailedParJobs.end(); it++)
{
free(*it);
}
}
void PrePostProcessor::Run()
@@ -484,7 +490,16 @@ void PrePostProcessor::ParCheckerUpdate(Subject * Caller, void * Aspect)
fclose(file);
}
}
bool bCollectionCompleted = IsCollectionCompleted(m_ParChecker.GetNZBFilename());
bool bHasFailedParJobs = HasFailedParJobs(m_ParChecker.GetNZBFilename());
if (g_pOptions->GetParCleanupQueue() && m_ParChecker.GetStatus() == ParChecker::psFinished &&
bCollectionCompleted && !bHasFailedParJobs)
{
ParCleanupQueue(m_ParChecker.GetNZBFilename());
}
int iParStatus = 0;
if (m_ParChecker.GetStatus() == ParChecker::psFailed)
{
@@ -502,16 +517,142 @@ void PrePostProcessor::ParCheckerUpdate(Subject * Caller, void * Aspect)
ExecPostScript(szPath, m_ParChecker.GetNZBFilename(), m_ParChecker.GetParFilename(), iParStatus);
m_mutexParChecker.Lock();
ParJob* pParJob = m_ParQueue.front();
m_ParQueue.pop_front();
delete pParJob;
m_bHasMoreJobs = !m_ParQueue.empty();
if (m_ParChecker.GetStatus() == ParChecker::psFailed && !bCollectionCompleted)
{
m_FailedParJobs.push_back(strdup(m_ParChecker.GetNZBFilename()));
}
if (bCollectionCompleted)
{
ClearFailedParJobs(m_ParChecker.GetNZBFilename());
}
m_mutexParChecker.Unlock();
}
}
/**
* Delete unneeded (paused) par-files from download queue after successful par-check.
* If the collection has paused non-par-files, none files will be deleted (even pars).
*/
void PrePostProcessor::ParCleanupQueue(const char* szNZBFilename)
{
// check if nzb-file has only pars paused
int ID = 0;
bool bOnlyPars = true;
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
for (DownloadQueue::iterator it = pDownloadQueue->begin(); it != pDownloadQueue->end(); it++)
{
FileInfo* pFileInfo = *it;
if (!strcmp(pFileInfo->GetNZBInfo()->GetFilename(), szNZBFilename))
{
ID = pFileInfo->GetID();
if (!pFileInfo->GetPaused() && !pFileInfo->GetDeleted() &&
!ParChecker::ParseParFilename(pFileInfo->GetFilename(), NULL, NULL))
{
bOnlyPars = false;
break;
}
}
}
g_pQueueCoordinator->UnlockQueue();
if (bOnlyPars && ID > 0)
{
char szNZBNiceName[1024];
NZBInfo::MakeNiceNZBName(szNZBFilename, szNZBNiceName, sizeof(szNZBNiceName));
info("Cleaning up download queue for %s", szNZBNiceName);
g_pQueueCoordinator->GetQueueEditor()->EditEntry(ID, false, QueueEditor::eaGroupDelete, 0);
}
}
/**
* Check if nzb-file has failures from other par-jobs
* (if nzb-file has more than one collections)
*/
bool PrePostProcessor::HasFailedParJobs(const char* szNZBFilename)
{
bool bHasFailedJobs = false;
m_mutexParChecker.Lock();
for (FileList::iterator it = m_FailedParJobs.begin(); it != m_FailedParJobs.end(); it++)
{
char* szNZBFilename = *it;
if (!strcmp(szNZBFilename, m_ParChecker.GetNZBFilename()))
{
bHasFailedJobs = true;
break;
}
}
m_mutexParChecker.Unlock();
return bHasFailedJobs;
}
/**
* Delete info about failed par-jobs for nzb-collection after the collection is completely downloaded.
* Mutex "m_mutexParChecker" must be locked prior to call of this funtion.
*/
void PrePostProcessor::ClearFailedParJobs(const char* szNZBFilename)
{
for (FileList::iterator it = m_FailedParJobs.begin(); it != m_FailedParJobs.end();)
{
char* szFailedNZBFilename = *it;
if (!strcmp(szNZBFilename, szFailedNZBFilename))
{
m_FailedParJobs.erase(it);
free(szFailedNZBFilename);
it = m_FailedParJobs.begin();
continue;
}
it++;
}
}
#endif
bool PrePostProcessor::IsCollectionCompleted(const char* szNZBFilename)
{
bool bCollectionCompleted = true;
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
for (DownloadQueue::iterator it = pDownloadQueue->begin(); it != pDownloadQueue->end(); it++)
{
FileInfo* pFileInfo = *it;
if (!pFileInfo->GetPaused() &&
!strcmp(pFileInfo->GetNZBInfo()->GetFilename(), szNZBFilename))
{
bCollectionCompleted = false;
break;
}
}
g_pQueueCoordinator->UnlockQueue();
#ifndef DISABLE_PARCHECK
if (bCollectionCompleted)
{
m_mutexParChecker.Lock();
for (ParQueue::iterator it = m_ParQueue.begin() + 1; it != m_ParQueue.end(); it++)
{
ParJob* pParJob = *it;
if (!strcmp(pParJob->GetNZBFilename(), szNZBFilename))
{
bCollectionCompleted = false;
break;
}
}
m_mutexParChecker.Unlock();
}
#endif
return bCollectionCompleted;
}
void PrePostProcessor::ExecPostScript(const char * szPath, const char * szNZBFilename, const char * szParFilename, int iParStatus)
{
const char* szScript = g_pOptions->GetPostProcess();
@@ -529,36 +670,7 @@ void PrePostProcessor::ExecPostScript(const char * szPath, const char * szNZBFil
return;
}
bool bCollectionCompleted = true;
DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue();
for (DownloadQueue::iterator it = pDownloadQueue->begin(); it != pDownloadQueue->end(); it++)
{
FileInfo* pFileInfo2 = *it;
if (!pFileInfo2->GetPaused() &&
!strcmp(pFileInfo2->GetNZBInfo()->GetFilename(), szNZBFilename))
{
bCollectionCompleted = false;
break;
}
}
g_pQueueCoordinator->UnlockQueue();
#ifndef DISABLE_PARCHECK
if (bCollectionCompleted)
{
m_mutexParChecker.Lock();
for (ParQueue::iterator it = m_ParQueue.begin(); it != m_ParQueue.end(); it++)
{
ParJob* pParJob = *it;
if (!strcmp(pParJob->GetNZBFilename(), szNZBFilename))
{
bCollectionCompleted = false;
break;
}
}
m_mutexParChecker.Unlock();
}
#endif
bool bCollectionCompleted = IsCollectionCompleted(szNZBFilename);
char szParStatus[10];
snprintf(szParStatus, 10, "%i", iParStatus);

View File

@@ -1,5 +1,5 @@
/*
* This file if part of nzbget
* This file is part of nzbget
*
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
*
@@ -83,10 +83,11 @@ private:
void CheckIncomingNZBs();
bool WasLastInCollection(DownloadQueue* pDownloadQueue, FileInfo* pFileInfo, bool bIgnorePaused);
void ExecPostScript(const char* szPath, const char* szNZBFilename, const char * szParFilename, int iParStatus);
bool IsCollectionCompleted(const char* szNZBFilename);
Mutex m_mutexParChecker;
ParQueue m_ParQueue;
FileList m_FailedParJobs;
#ifndef DISABLE_PARCHECK
ParChecker m_ParChecker;
@@ -98,6 +99,9 @@ private:
bool AddPar(FileInfo* pFileInfo, bool bDeleted);
bool SameParCollection(const char* szFilename1, const char* szFilename2);
bool FindMainPars(const char* szPath, FileList* pFileList);
void ParCleanupQueue(const char* szNZBFilename);
bool HasFailedParJobs(const char* szNZBFilename);
void ClearFailedParJobs(const char* szNZBFilename);
#endif
public:

View File

@@ -379,6 +379,14 @@ ParRepair=yes
# and the option "strictparname" does not change this behavior
StrictParName=yes
# Cleanup download queue after successful check/repair (yes, no)
# Enable this option for automatic deletion of unneeded (paused) par-files
# from download queue after successful check/repair.
# NOTE: before cleaning up the program checks if all paused files are par-files.
# If there are paused non-par-files (this means that you have paused them
# manually), the cleanup will be skipped for this collection.
ParCleanupQueue=yes
##############################################################################
### POSTPROCESSING ###