Skip to content

Commit

Permalink
Remove use of signals and slots from protocol server.
Browse files Browse the repository at this point in the history
The rewritten delete thread in libmythprotoserver was intended to be
ignorant of any metadata pertaining to the file it was deleting, and
simply implement the slow delete and follow symlinks features.  Signals
would be fired off to indicate success or failure of deletion, so other
code could handle removal of the metadata from the database.

This reworks that behavior, replacing the deletestruct with a
DeleteHandler class, and replacing the signals with DeleteSucceeded()
and DeleteFailed() virtual methods.  In order to handle metadata,
subclass this and overwrite those two methods.  FileServerHandler
accepts it using the HandleDeleteFile() method.
  • Loading branch information
wagnerrp committed Sep 8, 2011
1 parent 63746de commit 86d3537
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 105 deletions.
2 changes: 1 addition & 1 deletion mythtv/libs/libmythbase/mythversion.h
Expand Up @@ -12,7 +12,7 @@
/// Update this whenever the plug-in API changes. /// Update this whenever the plug-in API changes.
/// Including changes in the libmythbase, libmyth, libmythtv, libmythav* and /// Including changes in the libmythbase, libmyth, libmythtv, libmythav* and
/// libmythui class methods used by plug-ins. /// libmythui class methods used by plug-ins.
#define MYTH_BINARY_VERSION "0.25.20110907-2" #define MYTH_BINARY_VERSION "0.25.20110908-1"


/** \brief Increment this whenever the MythTV network protocol changes. /** \brief Increment this whenever the MythTV network protocol changes.
* *
Expand Down
117 changes: 59 additions & 58 deletions mythtv/libs/libmythprotoserver/requesthandler/deletethread.cpp
Expand Up @@ -12,9 +12,9 @@ using namespace std;
#include <QStringList> #include <QStringList>
#include <QMutexLocker> #include <QMutexLocker>


#include "requesthandler/deletethread.h"
#include "util.h" #include "util.h"
#include "mythdb.h" #include "mythdb.h"
#include "requesthandler/deletethread.h"
#include "mythcorecontext.h" #include "mythcorecontext.h"
#include "mythlogging.h" #include "mythlogging.h"


Expand All @@ -23,17 +23,14 @@ using namespace std;
that may be completely irrelevent to a machine that does not record, just that may be completely irrelevent to a machine that does not record, just
choose a reasonable value. choose a reasonable value.
38 Mbps (full QAM-256 multiplex) * 8 tuners = 9961472B/0.5s 38 Mbps (full QAM-256 multiplex) * 4 tuners = 9961472B/0.5s
*/ */


DeleteThread::DeleteThread(void) : DeleteThread::DeleteThread(void) :
MThread("Delete"), m_increment(9961472), m_run(true), m_timeout(20000) MThread("Delete"), m_increment(9961472), m_run(true)
{ {
m_slow = (bool) gCoreContext->GetNumSetting("TruncateDeletesSlowly", 0); m_slow = (bool) gCoreContext->GetNumSetting("TruncateDeletesSlowly", 0);
m_link = (bool) gCoreContext->GetNumSetting("DeletesFollowLinks", 0); m_link = (bool) gCoreContext->GetNumSetting("DeletesFollowLinks", 0);

connect(&m_timer, SIGNAL(timeout()), this, SLOT(timeout()));
m_timer.start(m_timeout);
} }


void DeleteThread::run(void) void DeleteThread::run(void)
Expand All @@ -54,12 +51,8 @@ void DeleteThread::run(void)
{ {
// this will only happen if the program is closing, so fast // this will only happen if the program is closing, so fast
// deletion is not a problem // deletion is not a problem
QList<deletestruct *>::iterator i; QList<DeleteHandler*>::iterator i;
for (i = m_files.begin(); i != m_files.end(); ++i) (*i)->DownRef();
{
close((*i)->fd);
delete (*i);
}
} }
else else
LOG(VB_FILE, LOG_DEBUG, "Delete thread self-terminating due to idle."); LOG(VB_FILE, LOG_DEBUG, "Delete thread self-terminating due to idle.");
Expand All @@ -75,52 +68,62 @@ bool DeleteThread::AddFile(QString path)
return false; return false;


QMutexLocker lock(&m_newlock); QMutexLocker lock(&m_newlock);
m_newfiles << path; DeleteHandler *handler = new DeleteHandler(path);
m_newfiles << handler;
return true;
}

bool DeleteThread::AddFile(DeleteHandler *handler)
{
handler->UpRef();
QMutexLocker lock(&m_newlock);
m_newfiles << handler;
return true; return true;
} }


void DeleteThread::ProcessNew(void) void DeleteThread::ProcessNew(void)
{ {
// loop through new files, unlinking and adding for deletion // loop through new files, unlinking and adding for deletion
// until none are left // until none are left
// TODO: add support for symlinks


QDateTime ctime = QDateTime::currentDateTime(); QDateTime ctime = QDateTime::currentDateTime();


while (true) while (true)
{ {
// pull a new path from the stack // pull a new path from the stack
QString path; DeleteHandler *handler;
{ {
QMutexLocker lock(&m_newlock); QMutexLocker lock(&m_newlock);
if (!m_newfiles.isEmpty()) if (m_newfiles.isEmpty())
path = m_newfiles.takeFirst(); break;
else
handler = m_newfiles.takeFirst();
} }


// empty path given to delete thread, this should not happen // empty path given to delete thread, this should not happen
if (path.isEmpty()) //if (path.isEmpty())
continue; // continue;

m_timer.start(m_timeout);


const char *cpath = path.toLocal8Bit().constData(); QString path = handler->m_path;
const char *cpath = handler->m_path.toLocal8Bit().constData();


QFileInfo finfo(path); QFileInfo finfo(handler->m_path);
if (finfo.isSymLink()) if (finfo.isSymLink())
{ {
if (m_link) if (m_link)
{ {
// if file is a symlink and symlinks are processed, // if file is a symlink and symlinks are processed,
// grab the target of the link, and attempt to unlink // grab the target of the link, and attempt to unlink
// the link itself // the link itself
QString tmppath = getSymlinkTarget(path); QString tmppath = getSymlinkTarget(handler->m_path);


if (unlink(cpath)) if (unlink(cpath))
{ {
LOG(VB_GENERAL, LOG_ERR, LOG(VB_GENERAL, LOG_ERR,
QString("Error deleting '%1' -> '%2': ") QString("Error deleting '%1' -> '%2': ")
.arg(path).arg(tmppath) + ENO); .arg(handler->m_path).arg(tmppath) + ENO);
emit unlinkFailed(path); handler->DeleteFailed();
handler->DownRef();
continue; continue;
} }


Expand All @@ -132,9 +135,9 @@ void DeleteThread::ProcessNew(void)
// signalling the matching metadata for removal, but the // signalling the matching metadata for removal, but the
// target itself fails, resulting in a spurious file in // target itself fails, resulting in a spurious file in
// an external directory with no link into mythtv // an external directory with no link into mythtv
emit fileUnlinked(path); handler->DeleteSucceeded();
path = tmppath; handler->m_path = tmppath;
cpath = path.toLocal8Bit().constData(); cpath = handler->m_path.toLocal8Bit().constData();
} }
else else
{ {
Expand All @@ -145,25 +148,27 @@ void DeleteThread::ProcessNew(void)
LOG(VB_GENERAL, LOG_ERR, LOG(VB_GENERAL, LOG_ERR,
QString("Error deleting '%1': count not unlink ") QString("Error deleting '%1': count not unlink ")
.arg(path) + ENO); .arg(path) + ENO);
emit unlinkFailed(path); handler->DeleteFailed();
} }
else else
emit fileUnlinked(path); handler->DeleteFailed();


handler->DownRef();
continue; continue;
} }
} }


// open the file so it can be unlinked without immediate deletion // open the file so it can be unlinked without immediate deletion
LOG(VB_FILE, LOG_INFO, QString("About to unlink/delete file: '%1'") LOG(VB_FILE, LOG_INFO, QString("About to unlink/delete file: '%1'")
.arg(path)); .arg(handler->m_path));
int fd = open(cpath, O_WRONLY); int fd = open(cpath, O_WRONLY);
if (fd == -1) if (fd == -1)
{ {
LOG(VB_GENERAL, LOG_ERR, LOG(VB_GENERAL, LOG_ERR,
QString("Error deleting '%1': could not open ") QString("Error deleting '%1': could not open ")
.arg(path) + ENO); .arg(handler->m_path) + ENO);
emit unlinkFailed(path); handler->DeleteFailed();
handler->DownRef();
continue; continue;
} }


Expand All @@ -174,22 +179,21 @@ void DeleteThread::ProcessNew(void)
LOG(VB_GENERAL, LOG_ERR, LOG(VB_GENERAL, LOG_ERR,
QString("Error deleting '%1': could not unlink ") QString("Error deleting '%1': could not unlink ")
.arg(path) + ENO); .arg(path) + ENO);
emit unlinkFailed(path); handler->DeleteFailed();
close(fd); close(fd);
handler->DownRef();
continue; continue;
} }


emit fileUnlinked(path); handler->DeleteSucceeded();


// insert the file into a queue of opened references to be deleted // insert the file into a queue of opened references to be deleted
deletestruct *ds = new deletestruct; handler->m_fd = fd;
ds->path = path; handler->m_size = finfo.size();
ds->fd = fd; handler->m_wait = ctime.addSecs(3); // delay deletion a bit to allow
ds->size = finfo.size(); // UI to get any needed IO time
ds->wait = ctime.addSecs(3); // delay deletion a bit to allow
// UI to get any needed IO time m_files << handler;

m_files << ds;
} }
} }


Expand All @@ -199,41 +203,38 @@ void DeleteThread::ProcessOld(void)
if (m_files.empty()) if (m_files.empty())
return; return;


// files exist for deletion, reset the timer
m_timer.start(m_timeout);

QDateTime ctime = QDateTime::currentDateTime(); QDateTime ctime = QDateTime::currentDateTime();


// only operate on one file at a time // only operate on one file at a time
// delete that file completely before moving onto the next // delete that file completely before moving onto the next
while (true) while (true)
{ {
deletestruct *ds = m_files.first(); DeleteHandler *handler = m_files.first();


// first file in the list has been delayed for deletion // first file in the list has been delayed for deletion
if (ds->wait > ctime) if (handler->m_wait > ctime)
break; break;

if (m_slow) if (m_slow)
{ {
ds->size -= m_increment; handler->m_size -= m_increment;
int err = ftruncate(ds->fd, ds->size); int err = ftruncate(handler->m_fd, handler->m_size);


if (err) if (err)
{ {
LOG(VB_GENERAL, LOG_ERR, QString("Error truncating '%1'") LOG(VB_GENERAL, LOG_ERR, QString("Error truncating '%1'")
.arg(ds->path) + ENO); .arg(handler->m_path) + ENO);
ds->size = 0; handler->m_size = 0;
} }
} }
else else
ds->size = 0; handler->m_size = 0;


if (ds->size == 0) if (handler->m_size == 0)
{ {
close(ds->fd); handler->Close();
m_files.removeFirst(); m_files.removeFirst();
delete ds; handler->DownRef();
} }


// fast delete can close out all, but slow delete needs // fast delete can close out all, but slow delete needs
Expand Down
26 changes: 6 additions & 20 deletions mythtv/libs/libmythprotoserver/requesthandler/deletethread.h
Expand Up @@ -17,14 +17,7 @@ using namespace std;


// MythTV headers // MythTV headers
#include "mthread.h" #include "mthread.h"

#include "requesthandler/fileserverutil.h"
typedef struct deletestruct
{
QString path;
int fd;
off_t size;
QDateTime wait;
} DeleteStruct;


class DeleteThread : public QObject, public MThread class DeleteThread : public QObject, public MThread
{ {
Expand All @@ -33,13 +26,8 @@ class DeleteThread : public QObject, public MThread
DeleteThread(void); DeleteThread(void);
void run(void); void run(void);
bool AddFile(QString path); bool AddFile(QString path);

bool AddFile(DeleteHandler *handler);
signals: void Stop(void) { m_run = false; }
void fileUnlinked(QString path);
void unlinkFailed(QString path);

private slots:
void timeout(void) { m_run = false; }


private: private:
void ProcessNew(void); void ProcessNew(void);
Expand All @@ -49,13 +37,11 @@ class DeleteThread : public QObject, public MThread
bool m_slow; bool m_slow;
bool m_link; bool m_link;
bool m_run; bool m_run;
QTimer m_timer;
int m_timeout;


QStringList m_newfiles; QList<DeleteHandler*> m_newfiles;
QMutex m_newlock; QMutex m_newlock;


QList<deletestruct*> m_files; QList<DeleteHandler*> m_files;
}; };


#endif #endif
30 changes: 15 additions & 15 deletions mythtv/libs/libmythprotoserver/requesthandler/fileserverhandler.cpp
Expand Up @@ -156,23 +156,17 @@ QString FileServerHandler::LocalFilePath(const QUrl &url,


void FileServerHandler::RunDeleteThread(void) void FileServerHandler::RunDeleteThread(void)
{ {
if (deletethread == NULL) if (deletethread != NULL)
{ {
deletethread = new DeleteThread(); if (deletethread->isRunning())
connect(deletethread, SIGNAL(unlinkFailed(QString)), return
this, SIGNAL(unlinkFailed(QString)));
connect(deletethread, SIGNAL(fileUnlinked(QString)), delete deletethread;
this, SIGNAL(fileUnlinked(QString))); deletethread = NULL;
connect(deletethread->qthread(), SIGNAL(finished()),
this, SLOT(deleteThreadTerminated()));
deletethread->start();
} }
}


void FileServerHandler::deleteThreadTerminated(void) deletethread = new DeleteThread();
{ deletethread->start();
delete deletethread;
deletethread = NULL;
} }


bool FileServerHandler::HandleAnnounce(MythSocket *socket, bool FileServerHandler::HandleAnnounce(MythSocket *socket,
Expand Down Expand Up @@ -730,7 +724,7 @@ bool FileServerHandler::HandleDeleteFile(SocketHandler *socket,


bool FileServerHandler::DeleteFile(QString filename, QString storagegroup) bool FileServerHandler::DeleteFile(QString filename, QString storagegroup)
{ {
return HandleDeleteFile(NULL, filename, storagegroup); return HandleDeleteFile( (SocketHandler *)NULL, filename, storagegroup);
} }


bool FileServerHandler::HandleDeleteFile(SocketHandler *socket, bool FileServerHandler::HandleDeleteFile(SocketHandler *socket,
Expand Down Expand Up @@ -795,6 +789,12 @@ bool FileServerHandler::HandleDeleteFile(SocketHandler *socket,
return true; return true;
} }


bool FileServerHandler::HandleDeleteFile(DeleteHandler *handler)
{
RunDeleteThread();
deletethread->AddFile(handler);
}

bool FileServerHandler::HandleGetFileList(SocketHandler *socket, bool FileServerHandler::HandleGetFileList(SocketHandler *socket,
QStringList &slist) QStringList &slist)
{ {
Expand Down

0 comments on commit 86d3537

Please sign in to comment.