Initial fix to high CPU usage when running in monitor mode (#165)

* Add skilion commit c2cdb24131
* Add skilion commit b702afda50
This commit is contained in:
abraunegg 2018-09-13 08:43:29 +10:00 committed by GitHub
parent 4919a58246
commit 564a77fb4e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 33 additions and 41 deletions

View file

@ -347,9 +347,8 @@ int main(string[] args)
// performSync complete, set lastCheckTime to current time // performSync complete, set lastCheckTime to current time
lastCheckTime = MonoTime.currTime(); lastCheckTime = MonoTime.currTime();
GC.collect(); GC.collect();
} else { }
Thread.sleep(dur!"msecs"(100)); Thread.sleep(dur!"msecs"(500));
}
} }
} }
} }

View file

@ -8,8 +8,8 @@ import util;
static import log; static import log;
// relevant inotify events // relevant inotify events
private immutable uint32_t mask = IN_ATTRIB | IN_CLOSE_WRITE | IN_CREATE | private immutable uint32_t mask = IN_CLOSE_WRITE | IN_CREATE | IN_DELETE |
IN_DELETE | IN_MOVE | IN_IGNORED | IN_Q_OVERFLOW; IN_MOVE | IN_IGNORED | IN_Q_OVERFLOW;
class MonitorException: ErrnoException class MonitorException: ErrnoException
{ {
@ -50,9 +50,10 @@ final class Monitor
{ {
this.verbose = verbose; this.verbose = verbose;
this.skip_symlinks = skip_symlinks; this.skip_symlinks = skip_symlinks;
assert(onDirCreated && onFileChanged && onDelete && onMove);
fd = inotify_init(); fd = inotify_init();
if (fd == -1) throw new MonitorException("inotify_init failed"); if (fd < 0) throw new MonitorException("inotify_init failed");
if (!buffer) buffer = new void[4096]; if (!buffer) buffer = new void[4096];
addRecursive("."); addRecursive(".");
} }
@ -92,26 +93,21 @@ final class Monitor
} }
} }
private void add(string dirname) private void add(string pathname)
{ {
int wd = inotify_add_watch(fd, toStringz(dirname), mask); int wd = inotify_add_watch(fd, toStringz(pathname), mask);
if (wd == -1) { if (wd < 0) {
if (errno() == ENOSPC) { if (errno() == ENOSPC) {
log.log("The maximum number of inotify watches is probably too low."); log.log("The user limit on the total number of inotify watches has been reached.");
log.log(""); log.log("To see the current max number of watches run:");
log.log("To see the current max number of watches run"); log.log("sysctl fs.inotify.max_user_watches");
log.log(""); log.log("To change the current max number of watches to 524288 run:");
log.log(" sysctl fs.inotify.max_user_watches"); log.log("sudo sysctl fs.inotify.max_user_watches=524288");
log.log(""); }
log.log("To change the current max number of watches to 32768 run"); throw new MonitorException("inotify_add_watch failed");
log.log(""); }
log.log(" sudo sysctl fs.inotify.max_user_watches=32768"); wdToDirName[wd] = buildNormalizedPath(pathname) ~ "/";
log.log(""); log.vlog("Monitor directory: ", pathname);
}
throw new MonitorException("inotify_add_watch failed");
}
wdToDirName[wd] = buildNormalizedPath(dirname) ~ "/";
log.vlog("Monitor directory: ", dirname);
} }
// remove a watch descriptor // remove a watch descriptor
@ -119,7 +115,7 @@ final class Monitor
{ {
assert(wd in wdToDirName); assert(wd in wdToDirName);
int ret = inotify_rm_watch(fd, wd); int ret = inotify_rm_watch(fd, wd);
if (ret == -1) throw new MonitorException("inotify_rm_watch failed"); if (ret < 0) throw new MonitorException("inotify_rm_watch failed");
log.vlog("Monitored directory removed: ", wdToDirName[wd]); log.vlog("Monitored directory removed: ", wdToDirName[wd]);
wdToDirName.remove(wd); wdToDirName.remove(wd);
} }
@ -131,7 +127,7 @@ final class Monitor
foreach (wd, dirname; wdToDirName) { foreach (wd, dirname; wdToDirName) {
if (dirname.startsWith(path)) { if (dirname.startsWith(path)) {
int ret = inotify_rm_watch(fd, wd); int ret = inotify_rm_watch(fd, wd);
if (ret == -1) throw new MonitorException("inotify_rm_watch failed"); if (ret < 0) throw new MonitorException("inotify_rm_watch failed");
wdToDirName.remove(wd); wdToDirName.remove(wd);
log.vlog("Monitored directory removed: ", dirname); log.vlog("Monitored directory removed: ", dirname);
} }
@ -148,18 +144,17 @@ final class Monitor
void update(bool useCallbacks = true) void update(bool useCallbacks = true)
{ {
assert(onDirCreated && onFileChanged && onDelete && onMove); pollfd fds = {
pollfd[1] fds = void; fd: fd,
fds[0].fd = fd; events: POLLIN
fds[0].events = POLLIN; };
while (true) { while (true) {
int ret = poll(fds.ptr, 1, 0); int ret = poll(&fds, 1, 0);
if (ret == -1) throw new MonitorException("poll failed"); if (ret == -1) throw new MonitorException("poll failed");
else if (ret == 0) break; // no events available else if (ret == 0) break; // no events available
assert(fds[0].revents & POLLIN); size_t length = read(fd, buffer.ptr, buffer.length);
size_t length = read(fds[0].fd, buffer.ptr, buffer.length);
if (length == -1) throw new MonitorException("read failed"); if (length == -1) throw new MonitorException("read failed");
int i = 0; int i = 0;
@ -207,18 +202,16 @@ final class Monitor
} }
} else if (event.mask & IN_DELETE) { } else if (event.mask & IN_DELETE) {
if (useCallbacks) onDelete(path); if (useCallbacks) onDelete(path);
} else if (event.mask & IN_ATTRIB || event.mask & IN_CLOSE_WRITE) { } else if ((event.mask & IN_CLOSE_WRITE) && !(event.mask & IN_ISDIR)) {
if (!(event.mask & IN_ISDIR)) { if (useCallbacks) onFileChanged(path);
if (useCallbacks) onFileChanged(path);
}
} else { } else {
log.log("Unknown inotify event: ", format("%#x", event.mask)); assert(0);
} }
skip: skip:
i += inotify_event.sizeof + event.len; i += inotify_event.sizeof + event.len;
} }
// assume that the items moved outside the watched directory has been deleted // assume that the items moved outside the watched directory have been deleted
foreach (cookie, path; cookieToPath) { foreach (cookie, path; cookieToPath) {
if (useCallbacks) onDelete(path); if (useCallbacks) onDelete(path);
remove(path); remove(path);