MythTV
master
mythtv
libs
libmythprotoserver
requesthandler
deletethread.cpp
Go to the documentation of this file.
1
#include <cstdlib>
2
#include <iostream>
3
#include <fcntl.h>
4
5
#include <QList>
6
#include <QTimer>
7
#include <QString>
8
#include <QFileInfo>
9
#include <QDateTime>
10
#include <QStringList>
11
#include <QMutexLocker>
12
13
#include "
libmythbase/mythcorecontext.h
"
14
#include "
libmythbase/mythdb.h
"
15
#include "
libmythbase/mythlogging.h
"
16
#include "
libmythbase/mythmiscutil.h
"
17
18
#include "
requesthandler/deletethread.h
"
19
20
/*
21
Rather than attempt to calculate a delete speed from tuner card information
22
that may be completely irrelevent to a machine that does not record, just
23
choose a reasonable value.
24
25
38 Mbps (full QAM-256 multiplex) * 4 tuners = 9961472B/0.5s
26
*/
27
28
DeleteThread::DeleteThread
(
void
) :
29
MThread
(
"Delete"
)
30
{
31
m_slow
= (
bool
)
gCoreContext
->
GetNumSetting
(
"TruncateDeletesSlowly"
, 0);
32
m_link
= (
bool
)
gCoreContext
->
GetNumSetting
(
"DeletesFollowLinks"
, 0);
33
}
34
35
void
DeleteThread::run
(
void
)
36
{
37
RunProlog
();
38
39
LOG
(VB_FILE, LOG_DEBUG,
"Spawning new delete thread."
);
40
41
while
(
gCoreContext
&&
m_run
)
42
{
43
// loop through any stored files every half second
44
ProcessNew
();
45
ProcessOld
();
46
usleep
(0.5s);
47
}
48
49
if
(!
m_files
.empty())
50
{
51
// this will only happen if the program is closing, so fast
52
// deletion is not a problem
53
QList<DeleteHandler*>::iterator i;
54
for
(i =
m_files
.begin(); i !=
m_files
.end(); ++i)
55
{
56
(*i)->Close();
57
(*i)->DecrRef();
58
}
59
m_files
.clear();
60
}
61
else
62
{
63
LOG
(VB_FILE, LOG_DEBUG,
"Delete thread self-terminating due to idle."
);
64
}
65
66
RunEpilog
();
67
}
68
69
bool
DeleteThread::AddFile
(
const
QString& path)
70
{
71
// check if a file exists, and add to the list of new files to be deleted
72
QFileInfo finfo(path);
73
if
(!finfo.exists())
74
return
false
;
75
76
QMutexLocker lock(&
m_newlock
);
77
auto
*handler =
new
DeleteHandler
(path);
78
m_newfiles
<< handler;
79
return
true
;
80
}
81
82
bool
DeleteThread::AddFile
(
DeleteHandler
*handler)
83
{
84
handler->
IncrRef
();
85
QMutexLocker lock(&
m_newlock
);
86
m_newfiles
<< handler;
87
return
true
;
88
}
89
90
void
DeleteThread::ProcessNew
(
void
)
91
{
92
// loop through new files, unlinking and adding for deletion
93
// until none are left
94
95
QDateTime ctime =
MythDate::current
();
96
97
while
(
true
)
98
{
99
// pull a new path from the stack
100
DeleteHandler
*handler =
nullptr
;
101
{
102
QMutexLocker lock(&
m_newlock
);
103
if
(
m_newfiles
.isEmpty())
104
break
;
105
handler =
m_newfiles
.takeFirst();
106
}
107
108
// empty path given to delete thread, this should not happen
109
//if (path.isEmpty())
110
// continue;
111
112
QString path = handler->
m_path
;
113
QByteArray cpath_ba = handler->
m_path
.toLocal8Bit();
114
const
char
*cpath = cpath_ba.constData();
115
116
QFileInfo finfo(handler->
m_path
);
117
if
(finfo.isSymLink())
118
{
119
if
(
m_link
)
120
{
121
// if file is a symlink and symlinks are processed,
122
// grab the target of the link, and attempt to unlink
123
// the link itself
124
QString tmppath =
getSymlinkTarget
(handler->
m_path
);
125
126
if
(unlink(cpath))
127
{
128
LOG
(VB_GENERAL, LOG_ERR,
129
QString(
"Error deleting '%1' -> '%2': "
)
130
.arg(handler->
m_path
, tmppath) +
ENO
);
131
handler->
DeleteFailed
();
132
handler->
DecrRef
();
133
continue
;
134
}
135
136
// if successful, emit that the link has been removed,
137
// and continue processing the target of the link as
138
// normal
139
//
140
// this may cause problems in which the link is unlinked
141
// signalling the matching metadata for removal, but the
142
// target itself fails, resulting in a spurious file in
143
// an external directory with no link into mythtv
144
handler->
DeleteSucceeded
();
145
handler->
m_path
= tmppath;
146
cpath_ba = handler->
m_path
.toLocal8Bit();
147
cpath = cpath_ba.constData();
148
}
149
else
150
{
151
// symlinks are not followed, so unlink the link
152
// itself and continue
153
if
(unlink(cpath))
154
{
155
LOG
(VB_GENERAL, LOG_ERR,
156
QString(
"Error deleting '%1': count not unlink "
)
157
.arg(path) +
ENO
);
158
handler->
DeleteFailed
();
159
}
160
else
161
{
162
handler->
DeleteFailed
();
163
}
164
165
handler->
DecrRef
();
166
continue
;
167
}
168
}
169
170
// open the file so it can be unlinked without immediate deletion
171
LOG
(VB_FILE, LOG_INFO, QString(
"About to unlink/delete file: '%1'"
)
172
.arg(handler->
m_path
));
173
int
fd = open(cpath, O_WRONLY);
174
if
(fd == -1)
175
{
176
LOG
(VB_FILE, LOG_INFO, QString(
"About to unlink/delete file"
));
177
178
QDir dir(cpath);
179
if
(
MythRemoveDirectory
(dir))
180
{
181
LOG
(VB_GENERAL, LOG_ERR,
182
QString(
"Error deleting '%1': is no directory "
)
183
.arg(cpath) +
ENO
);
184
handler->
DeleteFailed
();
185
handler->
DecrRef
();
186
continue
;
187
}
188
}
189
// unlink the file so as soon as it is closed, the system will
190
// delete it from the filesystem
191
else
if
(unlink(cpath))
192
{
193
LOG
(VB_GENERAL, LOG_ERR,
194
QString(
"Error deleting '%1': could not unlink "
)
195
.arg(path) +
ENO
);
196
handler->
DeleteFailed
();
197
close
(fd);
198
handler->
DecrRef
();
199
continue
;
200
}
201
202
handler->
DeleteSucceeded
();
203
204
// insert the file into a queue of opened references to be deleted
205
handler->
m_fd
= fd;
206
handler->
m_size
= finfo.size();
207
handler->
m_wait
= ctime.addSecs(3);
// delay deletion a bit to allow
208
// UI to get any needed IO time
209
210
m_files
<< handler;
211
}
212
}
213
214
void
DeleteThread::ProcessOld
(
void
)
215
{
216
// im the only thread accessing this, so no need for a lock
217
if
(
m_files
.empty())
218
return
;
219
220
QDateTime ctime =
MythDate::current
();
221
222
// only operate on one file at a time
223
// delete that file completely before moving onto the next
224
while
(
true
)
225
{
226
DeleteHandler
*handler =
m_files
.first();
227
228
// first file in the list has been delayed for deletion
229
if
(handler->
m_wait
> ctime)
230
break
;
231
232
if
(
m_slow
)
233
{
234
handler->
m_size
-=
m_increment
;
235
int
err = ftruncate(handler->
m_fd
, handler->
m_size
);
236
237
if
(err)
238
{
239
LOG
(VB_GENERAL, LOG_ERR, QString(
"Error truncating '%1'"
)
240
.arg(handler->
m_path
) +
ENO
);
241
handler->
m_size
= 0;
242
}
243
}
244
else
245
{
246
handler->
m_size
= 0;
247
}
248
249
if
(handler->
m_size
== 0)
250
{
251
handler->
Close
();
252
m_files
.removeFirst();
253
handler->
DecrRef
();
254
}
255
256
// fast delete can close out all, but slow delete needs
257
// to return to sleep
258
if
(
m_slow
||
m_files
.empty())
259
break
;
260
}
261
}
bool
bool
Definition:
pxsup2dast.c:30
ENO
#define ENO
This can be appended to the LOG args with "+".
Definition:
mythlogging.h:74
ReferenceCounter::DecrRef
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
Definition:
referencecounter.cpp:124
mythdb.h
DeleteHandler::m_fd
int m_fd
Definition:
fileserverutil.h:40
DeleteThread::AddFile
bool AddFile(const QString &path)
Definition:
deletethread.cpp:69
MThread::usleep
static void usleep(std::chrono::microseconds time)
Definition:
mthread.cpp:335
getSymlinkTarget
QString getSymlinkTarget(const QString &start_file, QStringList *intermediaries, unsigned maxLinks)
Definition:
mythmiscutil.cpp:451
DeleteThread::ProcessOld
void ProcessOld(void)
Definition:
deletethread.cpp:214
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition:
mythlogging.h:39
MThread::RunProlog
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition:
mthread.cpp:196
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition:
mythdate.cpp:15
close
#define close
Definition:
compat.h:43
MythRemoveDirectory
bool MythRemoveDirectory(QDir &aDir)
Definition:
mythmiscutil.cpp:759
DeleteHandler::DeleteSucceeded
virtual void DeleteSucceeded(void)
Definition:
fileserverutil.h:33
deletethread.h
mythlogging.h
DeleteThread::m_newlock
QMutex m_newlock
Definition:
deletethread.h:39
DeleteHandler
Definition:
fileserverutil.h:17
DeleteThread::m_newfiles
QList< DeleteHandler * > m_newfiles
Definition:
deletethread.h:38
DeleteThread::ProcessNew
void ProcessNew(void)
Definition:
deletethread.cpp:90
DeleteHandler::m_wait
QDateTime m_wait
Definition:
fileserverutil.h:42
DeleteHandler::m_size
off_t m_size
Definition:
fileserverutil.h:41
MThread::RunEpilog
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition:
mthread.cpp:209
DeleteThread::run
void run() override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition:
deletethread.cpp:35
DeleteHandler::m_path
QString m_path
Definition:
fileserverutil.h:39
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition:
mythcorecontext.cpp:57
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition:
mythcorecontext.cpp:918
DeleteThread::m_increment
size_t m_increment
Definition:
deletethread.h:33
mythmiscutil.h
DeleteThread::m_link
bool m_link
Definition:
deletethread.h:35
mythcorecontext.h
DeleteThread::DeleteThread
DeleteThread(void)
Definition:
deletethread.cpp:28
DeleteHandler::DeleteFailed
virtual void DeleteFailed(void)
Definition:
fileserverutil.h:34
MThread
This is a wrapper around QThread that does several additional things.
Definition:
mthread.h:48
DeleteThread::m_run
bool m_run
Definition:
deletethread.h:36
DeleteHandler::Close
void Close(void)
Definition:
fileserverutil.cpp:36
ReferenceCounter::IncrRef
virtual int IncrRef(void)
Increments reference count.
Definition:
referencecounter.cpp:100
DeleteThread::m_files
QList< DeleteHandler * > m_files
Definition:
deletethread.h:41
DeleteThread::m_slow
bool m_slow
Definition:
deletethread.h:34
Generated on Wed Feb 26 2025 03:17:55 for MythTV by
1.8.17