MythTV
master
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
LOG
(VB_FILE, LOG_DEBUG,
"Delete thread self-terminating due to idle."
);
63
64
RunEpilog
();
65
}
66
67
bool
DeleteThread::AddFile
(
const
QString& path)
68
{
69
// check if a file exists, and add to the list of new files to be deleted
70
QFileInfo finfo(path);
71
if
(!finfo.exists())
72
return
false
;
73
74
QMutexLocker lock(&
m_newlock
);
75
auto
*handler =
new
DeleteHandler
(path);
76
m_newfiles
<< handler;
77
return
true
;
78
}
79
80
bool
DeleteThread::AddFile
(
DeleteHandler
*handler)
81
{
82
handler->
IncrRef
();
83
QMutexLocker lock(&
m_newlock
);
84
m_newfiles
<< handler;
85
return
true
;
86
}
87
88
void
DeleteThread::ProcessNew
(
void
)
89
{
90
// loop through new files, unlinking and adding for deletion
91
// until none are left
92
93
QDateTime ctime =
MythDate::current
();
94
95
while
(
true
)
96
{
97
// pull a new path from the stack
98
DeleteHandler
*handler =
nullptr
;
99
{
100
QMutexLocker lock(&
m_newlock
);
101
if
(
m_newfiles
.isEmpty())
102
break
;
103
handler =
m_newfiles
.takeFirst();
104
}
105
106
// empty path given to delete thread, this should not happen
107
//if (path.isEmpty())
108
// continue;
109
110
QString path = handler->
m_path
;
111
QByteArray cpath_ba = handler->
m_path
.toLocal8Bit();
112
const
char
*cpath = cpath_ba.constData();
113
114
QFileInfo finfo(handler->
m_path
);
115
if
(finfo.isSymLink())
116
{
117
if
(
m_link
)
118
{
119
// if file is a symlink and symlinks are processed,
120
// grab the target of the link, and attempt to unlink
121
// the link itself
122
QString tmppath =
getSymlinkTarget
(handler->
m_path
);
123
124
if
(unlink(cpath))
125
{
126
LOG
(VB_GENERAL, LOG_ERR,
127
QString(
"Error deleting '%1' -> '%2': "
)
128
.arg(handler->
m_path
, tmppath) +
ENO
);
129
handler->
DeleteFailed
();
130
handler->
DecrRef
();
131
continue
;
132
}
133
134
// if successful, emit that the link has been removed,
135
// and continue processing the target of the link as
136
// normal
137
//
138
// this may cause problems in which the link is unlinked
139
// signalling the matching metadata for removal, but the
140
// target itself fails, resulting in a spurious file in
141
// an external directory with no link into mythtv
142
handler->
DeleteSucceeded
();
143
handler->
m_path
= tmppath;
144
cpath_ba = handler->
m_path
.toLocal8Bit();
145
cpath = cpath_ba.constData();
146
}
147
else
148
{
149
// symlinks are not followed, so unlink the link
150
// itself and continue
151
if
(unlink(cpath))
152
{
153
LOG
(VB_GENERAL, LOG_ERR,
154
QString(
"Error deleting '%1': count not unlink "
)
155
.arg(path) +
ENO
);
156
handler->
DeleteFailed
();
157
}
158
else
159
handler->
DeleteFailed
();
160
161
handler->
DecrRef
();
162
continue
;
163
}
164
}
165
166
// open the file so it can be unlinked without immediate deletion
167
LOG
(VB_FILE, LOG_INFO, QString(
"About to unlink/delete file: '%1'"
)
168
.arg(handler->
m_path
));
169
int
fd = open(cpath, O_WRONLY);
170
if
(fd == -1)
171
{
172
LOG
(VB_FILE, LOG_INFO, QString(
"About to unlink/delete file"
));
173
174
QDir dir(cpath);
175
if
(
MythRemoveDirectory
(dir))
176
{
177
LOG
(VB_GENERAL, LOG_ERR,
178
QString(
"Error deleting '%1': is no directory "
)
179
.arg(cpath) +
ENO
);
180
handler->
DeleteFailed
();
181
handler->
DecrRef
();
182
continue
;
183
}
184
}
185
// unlink the file so as soon as it is closed, the system will
186
// delete it from the filesystem
187
else
if
(unlink(cpath))
188
{
189
LOG
(VB_GENERAL, LOG_ERR,
190
QString(
"Error deleting '%1': could not unlink "
)
191
.arg(path) +
ENO
);
192
handler->
DeleteFailed
();
193
close
(fd);
194
handler->
DecrRef
();
195
continue
;
196
}
197
198
handler->
DeleteSucceeded
();
199
200
// insert the file into a queue of opened references to be deleted
201
handler->
m_fd
= fd;
202
handler->
m_size
= finfo.size();
203
handler->
m_wait
= ctime.addSecs(3);
// delay deletion a bit to allow
204
// UI to get any needed IO time
205
206
m_files
<< handler;
207
}
208
}
209
210
void
DeleteThread::ProcessOld
(
void
)
211
{
212
// im the only thread accessing this, so no need for a lock
213
if
(
m_files
.empty())
214
return
;
215
216
QDateTime ctime =
MythDate::current
();
217
218
// only operate on one file at a time
219
// delete that file completely before moving onto the next
220
while
(
true
)
221
{
222
DeleteHandler
*handler =
m_files
.first();
223
224
// first file in the list has been delayed for deletion
225
if
(handler->
m_wait
> ctime)
226
break
;
227
228
if
(
m_slow
)
229
{
230
handler->
m_size
-=
m_increment
;
231
int
err = ftruncate(handler->
m_fd
, handler->
m_size
);
232
233
if
(err)
234
{
235
LOG
(VB_GENERAL, LOG_ERR, QString(
"Error truncating '%1'"
)
236
.arg(handler->
m_path
) +
ENO
);
237
handler->
m_size
= 0;
238
}
239
}
240
else
241
handler->
m_size
= 0;
242
243
if
(handler->
m_size
== 0)
244
{
245
handler->
Close
();
246
m_files
.removeFirst();
247
handler->
DecrRef
();
248
}
249
250
// fast delete can close out all, but slow delete needs
251
// to return to sleep
252
if
(
m_slow
||
m_files
.empty())
253
break
;
254
}
255
}
bool
bool
Definition:
pxsup2dast.c:30
ENO
#define ENO
This can be appended to the LOG args with "+".
Definition:
mythlogging.h:73
ReferenceCounter::DecrRef
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
Definition:
referencecounter.cpp:125
mythdb.h
DeleteHandler::m_fd
int m_fd
Definition:
fileserverutil.h:40
DeleteThread::AddFile
bool AddFile(const QString &path)
Definition:
deletethread.cpp:67
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:210
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:14
close
#define close
Definition:
compat.h:43
MythRemoveDirectory
bool MythRemoveDirectory(QDir &aDir)
Definition:
mythmiscutil.cpp:756
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:88
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:55
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition:
mythcorecontext.cpp:911
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:101
DeleteThread::m_files
QList< DeleteHandler * > m_files
Definition:
deletethread.h:41
DeleteThread::m_slow
bool m_slow
Definition:
deletethread.h:34
Generated on Mon Nov 27 2023 03:19:42 for MythTV by
1.8.17